From 4c769dfbf96319ebeb1cf8fa2396bb8554fe1a32 Mon Sep 17 00:00:00 2001 From: nmzik Date: Sun, 6 Sep 2026 03:46:34 +0400 Subject: [PATCH] render: simplify buffer and memory tracking ownership --- src/graphics/host_gpu/graphicContext.h | 7 -- src/graphics/host_gpu/memoryTracker.cpp | 18 +---- src/graphics/host_gpu/memoryTracker.h | 2 - src/graphics/host_gpu/pageManager.cpp | 4 - src/graphics/host_gpu/pageManager.h | 2 - .../renderer/cache/gpuResourceManager.cpp | 2 - .../host_gpu/renderer/cache/streamBuffer.cpp | 53 ++++++------ .../host_gpu/renderer/cache/streamBuffer.h | 8 +- src/graphics/host_gpu/vma.cpp | 81 ++----------------- src/graphics/host_gpu/vma.h | 1 - tests/MemoryTrackerTests.cpp | 31 +++---- tests/PageManagerTests.cpp | 18 ----- tests/ShaderRecompilerComputeTests.cpp | 2 - 13 files changed, 50 insertions(+), 179 deletions(-) diff --git a/src/graphics/host_gpu/graphicContext.h b/src/graphics/host_gpu/graphicContext.h index 5f271f48b..4e156792a 100644 --- a/src/graphics/host_gpu/graphicContext.h +++ b/src/graphics/host_gpu/graphicContext.h @@ -93,11 +93,8 @@ struct GraphicContext { [[nodiscard]] bool CanReportMemoryUsage() const noexcept { return memory_budget_ext_enabled; } [[nodiscard]] uint64_t GetDeviceMemoryUsage() const; [[nodiscard]] uint64_t GetTotalMemoryBudget() const; - void CreateBuffer(uint64_t size, VulkanBuffer& buffer); [[nodiscard]] bool CreateImage(const vk::ImageCreateInfo& info, VulkanImage& image); void DeleteImage(VulkanImage& image); - void MapMemory(VulkanMemory& memory, void*& data); - void UnmapMemory(VulkanMemory& memory); void AppendHardwareRayTracingDeviceExtensions( const std::vector& available_extensions, std::vector& device_extensions); @@ -120,12 +117,8 @@ struct VulkanMemory { vk::MemoryRequirements requirements = {}; vk::MemoryPropertyFlags property = {}; vk::MemoryPropertyFlags preferred_property = {}; - vk::DeviceMemory memory = nullptr; VmaAllocation allocation = nullptr; - VmaAllocationInfo allocation_info = {}; - vk::DeviceSize offset = 0; uint32_t type = 0; - uint64_t unique_id = 0; }; struct VulkanImageState { diff --git a/src/graphics/host_gpu/memoryTracker.cpp b/src/graphics/host_gpu/memoryTracker.cpp index d853a86b6..f49b84ba1 100644 --- a/src/graphics/host_gpu/memoryTracker.cpp +++ b/src/graphics/host_gpu/memoryTracker.cpp @@ -23,10 +23,7 @@ void MemoryTracker::ValidateGpuDirtyPages(const RangeSet& dirty, uint64_t vaddr, EXIT("MemoryTracker: invalid dirty-page validation range\n"); } for (auto page = vaddr; page < vaddr + size; page += TRACKER_PAGE_SIZE) { - bool found = false; - dirty.ForEachIntersection(page, TRACKER_PAGE_SIZE, - [&found](RangeSet::Range) { found = true; }); - if (!found) { + if (!dirty.Intersects(page, TRACKER_PAGE_SIZE)) { EXIT("MemoryTracker: GPU-dirty tracker page has no dirty bytes, operation=%s " "addr=0x%016" PRIx64 "\n", operation, page); @@ -40,9 +37,7 @@ void MemoryTracker::ValidateGpuDirtyOwnership(const RangeSet& dirty, uint64_t va const auto begin = vaddr & ~(TRACKER_PAGE_SIZE - 1); const auto end = (vaddr + size + TRACKER_PAGE_SIZE - 1) & ~(TRACKER_PAGE_SIZE - 1); for (auto page = begin; page < end; page += TRACKER_PAGE_SIZE) { - bool has_dirty_bytes = false; - dirty.ForEachIntersection(page, TRACKER_PAGE_SIZE, - [&has_dirty_bytes](RangeSet::Range) { has_dirty_bytes = true; }); + const bool has_dirty_bytes = dirty.Intersects(page, TRACKER_PAGE_SIZE); if (IsRegionGpuModified(page, TRACKER_PAGE_SIZE) != has_dirty_bytes) { EXIT("MemoryTracker: tracker and byte ownership disagree, operation=%s " "addr=0x%016" PRIx64 "\n", @@ -113,7 +108,8 @@ void MemoryTracker::UnmarkRegionAsGpuModified(uint64_t vaddr, uint64_t size) { }); } -void MemoryTracker::UntrackMemoryImpl(uint64_t vaddr, uint64_t size) { +void MemoryTracker::UntrackMemory(uint64_t vaddr, uint64_t size) { + CheckNotInUploadCallback(); std::vector managers; managers.reserve((vaddr % TRACKER_REGION_SIZE + size + TRACKER_REGION_SIZE - 1) / TRACKER_REGION_SIZE); @@ -134,12 +130,6 @@ void MemoryTracker::UntrackMemoryImpl(uint64_t vaddr, uint64_t size) { Iterate(vaddr, size, [](RegionManager* manager, uint64_t offset, uint64_t bytes) { manager->ChangeState(manager->GetCpuAddr() + offset, bytes); }); - locks.clear(); -} - -void MemoryTracker::UntrackMemory(uint64_t vaddr, uint64_t size) { - CheckNotInUploadCallback(); - UntrackMemoryImpl(vaddr, size); } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/memoryTracker.h b/src/graphics/host_gpu/memoryTracker.h index 0394fcbcd..f2c2f45d1 100644 --- a/src/graphics/host_gpu/memoryTracker.h +++ b/src/graphics/host_gpu/memoryTracker.h @@ -34,7 +34,6 @@ public: void InvalidateRegion(uint64_t vaddr, uint64_t size, Flush&& on_flush) noexcept { static_assert(std::is_invocable_v); CheckNotInUploadCallback(); - ValidateRange(vaddr, size); Iterate(vaddr, size, [&](RegionManager* manager, uint64_t offset, uint64_t bytes) { const bool should_flush = [&] { @@ -171,7 +170,6 @@ private: } static void ValidateRange(uint64_t vaddr, uint64_t size); - void UntrackMemoryImpl(uint64_t vaddr, uint64_t size); RegionManager* GetOrCreateRegion(uint64_t index); std::unique_ptr[]> m_regions; diff --git a/src/graphics/host_gpu/pageManager.cpp b/src/graphics/host_gpu/pageManager.cpp index 9abf1de82..8f596e803 100644 --- a/src/graphics/host_gpu/pageManager.cpp +++ b/src/graphics/host_gpu/pageManager.cpp @@ -371,8 +371,4 @@ template void PageManager::UpdatePageWatchersForRegion(uint64_t, Re template void PageManager::UpdatePageWatchersForRegion(uint64_t, RegionBits&); template void PageManager::UpdatePageWatchersForRegion(uint64_t, RegionBits&); -void PageManager::OnGpuMap(uint64_t, uint64_t) {} - -void PageManager::OnGpuUnmap(uint64_t, uint64_t) {} - } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/pageManager.h b/src/graphics/host_gpu/pageManager.h index ed304eedd..a56795e9a 100644 --- a/src/graphics/host_gpu/pageManager.h +++ b/src/graphics/host_gpu/pageManager.h @@ -24,8 +24,6 @@ public: void UpdatePageWatchers(uint64_t vaddr, uint64_t size); template void UpdatePageWatchersForRegion(uint64_t base_addr, RegionBits& mask); - void OnGpuMap(uint64_t vaddr, uint64_t size); - void OnGpuUnmap(uint64_t vaddr, uint64_t size); private: struct Impl; diff --git a/src/graphics/host_gpu/renderer/cache/gpuResourceManager.cpp b/src/graphics/host_gpu/renderer/cache/gpuResourceManager.cpp index f49c63536..a65485d56 100644 --- a/src/graphics/host_gpu/renderer/cache/gpuResourceManager.cpp +++ b/src/graphics/host_gpu/renderer/cache/gpuResourceManager.cpp @@ -47,7 +47,6 @@ void GpuResourceManager::MapMemory(uint64_t vaddr, uint64_t size) { std::lock_guard lock(m_mapped_ranges_mutex); m_mapped_ranges.Add(vaddr, size); } - m_page_manager.OnGpuMap(vaddr, size); } void GpuResourceManager::UnmapMemory(uint64_t vaddr, uint64_t size) { @@ -64,7 +63,6 @@ void GpuResourceManager::UnmapMemory(uint64_t vaddr, uint64_t size) { } m_buffer_cache.InvalidateMemory(vaddr, size); m_texture_cache.UnmapMemory(vaddr, size); - m_page_manager.OnGpuUnmap(vaddr, size); std::lock_guard lock(m_mapped_ranges_mutex); m_mapped_ranges.Subtract(vaddr, size); }; diff --git a/src/graphics/host_gpu/renderer/cache/streamBuffer.cpp b/src/graphics/host_gpu/renderer/cache/streamBuffer.cpp index 2f47e9801..73b11d293 100644 --- a/src/graphics/host_gpu/renderer/cache/streamBuffer.cpp +++ b/src/graphics/host_gpu/renderer/cache/streamBuffer.cpp @@ -64,7 +64,7 @@ constexpr size_t WATCHES_RESERVE_CHUNK = 0x1000; Buffer::Buffer(GraphicContext& graphics, CommandScheduler& scheduler, MemoryUsage usage, uint64_t cpu_address, vk::BufferUsageFlags flags, uint64_t size) : m_graphics(&graphics), m_scheduler(&scheduler), m_usage(usage), m_cpu_address(cpu_address), - m_size(size), m_buffer(std::make_unique()) { + m_buffer(std::make_unique()) { KYTY_PROFILER_FUNCTION(); EXIT_IF(graphics.allocator == nullptr || size == 0); @@ -96,11 +96,7 @@ Buffer::Buffer(GraphicContext& graphics, CommandScheduler& scheduler, MemoryUsag m_buffer->buffer = native_buffer; m_buffer->usage = flags; m_buffer->buffer_size = size; - m_buffer->memory.allocation_info = allocation_result; - m_buffer->memory.memory = allocation_result.deviceMemory; - m_buffer->memory.offset = allocation_result.offset; m_buffer->memory.type = allocation_result.memoryType; - m_buffer->memory.unique_id = VulkanNextMemoryUniqueId(); graphics.device.getBufferMemoryRequirements(m_buffer->buffer, &m_buffer->memory.requirements); if (static_cast(flags & vk::BufferUsageFlagBits::eShaderDeviceAddress)) { vk::BufferDeviceAddressInfo address_info {}; @@ -112,7 +108,6 @@ Buffer::Buffer(GraphicContext& graphics, CommandScheduler& scheduler, MemoryUsag VkMemoryPropertyFlags properties = 0; vmaGetAllocationMemoryProperties(graphics.allocator, m_buffer->memory.allocation, &properties); m_buffer->memory.property = vk::MemoryPropertyFlags(properties); - m_is_coherent = (properties & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0; if (allocation_result.pMappedData != nullptr) { m_mapped = {static_cast(allocation_result.pMappedData), static_cast(size)}; @@ -131,24 +126,32 @@ vk::Buffer Buffer::Handle() const noexcept { return m_buffer->buffer; } +uint64_t Buffer::Size() const noexcept { + return m_buffer->buffer_size; +} + +bool Buffer::IsCoherent() const noexcept { + return bool(m_buffer->memory.property & vk::MemoryPropertyFlagBits::eHostCoherent); +} + vk::DeviceAddress Buffer::BufferDeviceAddress() const noexcept { EXIT_IF(m_device_address == 0); return m_device_address; } bool Buffer::IsInBounds(uint64_t address, uint64_t size) const noexcept { - return address >= m_cpu_address && size <= m_size && address - m_cpu_address <= m_size - size; + return address >= m_cpu_address && size <= Size() && address - m_cpu_address <= Size() - size; } void Buffer::Write(uint64_t offset, const void* source, uint64_t size) { - EXIT_IF(source == nullptr || m_mapped.empty() || offset > m_size || size > m_size - offset); + EXIT_IF(source == nullptr || m_mapped.empty() || offset > Size() || size > Size() - offset); std::memcpy(m_mapped.data() + offset, source, static_cast(size)); Flush(offset, size); } void Buffer::Flush(uint64_t offset, uint64_t size) { - EXIT_IF(m_mapped.empty() || offset > m_size || size > m_size - offset); - if (!m_is_coherent && size != 0) { + EXIT_IF(m_mapped.empty() || offset > Size() || size > Size() - offset); + if (!IsCoherent() && size != 0) { const auto result = vmaFlushAllocation(m_graphics->allocator, m_buffer->memory.allocation, offset, size); EXIT_NOT_IMPLEMENTED(static_cast(result) != vk::Result::eSuccess); @@ -156,8 +159,8 @@ void Buffer::Flush(uint64_t offset, uint64_t size) { } void Buffer::Invalidate(uint64_t offset, uint64_t size) { - EXIT_IF(m_usage != MemoryUsage::Download || offset > m_size || size > m_size - offset); - if (!m_is_coherent && size != 0) { + EXIT_IF(m_usage != MemoryUsage::Download || offset > Size() || size > Size() - offset); + if (!IsCoherent() && size != 0) { const auto result = vmaInvalidateAllocation(m_graphics->allocator, m_buffer->memory.allocation, offset, size); EXIT_NOT_IMPLEMENTED(static_cast(result) != vk::Result::eSuccess); @@ -166,10 +169,10 @@ void Buffer::Invalidate(uint64_t offset, uint64_t size) { vk::BufferMemoryBarrier Buffer::Barrier(uint64_t offset, uint64_t size, vk::AccessFlags source, vk::AccessFlags destination) const { - if (Handle() == nullptr || size == 0 || offset > m_size || size > m_size - offset) { + if (Handle() == nullptr || size == 0 || offset > Size() || size > Size() - offset) { EXIT("Buffer: invalid DMA barrier, handle=%p offset=0x%016" PRIx64 " size=0x%016" PRIx64 " capacity=0x%016" PRIx64 "\n", - static_cast(Handle()), offset, size, m_size); + static_cast(Handle()), offset, size, Size()); } vk::BufferMemoryBarrier barrier {}; barrier.srcAccessMask = source; @@ -186,8 +189,8 @@ void Buffer::CopyFrom(CommandBuffer& command, const Buffer& source, uint64_t sou uint64_t destination_offset, uint64_t size, vk::AccessFlags source_before, vk::AccessFlags destination_before, vk::AccessFlags source_after, vk::AccessFlags destination_after) { - if (size == 0 || source_offset > source.m_size || size > source.m_size - source_offset || - destination_offset > m_size || size > m_size - destination_offset) { + if (size == 0 || source_offset > source.Size() || size > source.Size() - source_offset || + destination_offset > Size() || size > Size() - destination_offset) { EXIT("Buffer: invalid copy range\n"); } if (source.Handle() == Handle() && source_offset < destination_offset + size && @@ -244,10 +247,8 @@ void Buffer::Fill(uint64_t offset, uint64_t size, uint32_t value) { StreamBuffer::StreamBuffer(GraphicContext& graphics, CommandScheduler& scheduler, MemoryUsage usage, uint64_t size) - : Buffer(graphics, scheduler, usage, 0, AllFlags, size) { - ReserveWatches(m_current_watches, WATCHES_INITIAL_RESERVE); - ReserveWatches(m_previous_watches, WATCHES_INITIAL_RESERVE); -} + : Buffer(graphics, scheduler, usage, 0, AllFlags, size), + m_current_watches(WATCHES_INITIAL_RESERVE), m_previous_watches(WATCHES_INITIAL_RESERVE) {} bool StreamBuffer::NormalizeReservation(bool coherent, uint64_t atom, uint64_t& size, uint64_t& alignment) { @@ -312,10 +313,8 @@ std::pair StreamBuffer::Map(uint64_t size, uint64_t alignmen } void StreamBuffer::Commit() { - if (!IsCoherent() && Usage() != MemoryUsage::Download && m_mapped_size != 0) { - const auto result = vmaFlushAllocation( - Graphics().allocator, NativeBuffer().memory.allocation, m_offset, m_mapped_size); - EXIT_NOT_IMPLEMENTED(static_cast(result) != vk::Result::eSuccess); + if (Usage() != MemoryUsage::Download && m_mapped_size != 0) { + Flush(m_offset, m_mapped_size); } m_offset += m_mapped_size; @@ -325,7 +324,7 @@ void StreamBuffer::Commit() { return; } if (m_current_watch_cursor + 1 >= m_current_watches.size()) { - ReserveWatches(m_current_watches, WATCHES_RESERVE_CHUNK); + m_current_watches.resize(m_current_watches.size() + WATCHES_RESERVE_CHUNK); } auto& watch = m_current_watches[m_current_watch_cursor++]; watch.upper_bound = m_offset; @@ -341,10 +340,6 @@ uint64_t StreamBuffer::Copy(const void* source, uint64_t size, uint64_t alignmen return offset; } -void StreamBuffer::ReserveWatches(std::vector& watches, size_t grow_size) { - watches.resize(watches.size() + grow_size); -} - bool StreamBuffer::WaitPendingOperations(const std::vector& watches, std::optional invalidation_mark, uint64_t requested_upper_bound, bool allow_wait, diff --git a/src/graphics/host_gpu/renderer/cache/streamBuffer.h b/src/graphics/host_gpu/renderer/cache/streamBuffer.h index a40403508..0334e2de2 100644 --- a/src/graphics/host_gpu/renderer/cache/streamBuffer.h +++ b/src/graphics/host_gpu/renderer/cache/streamBuffer.h @@ -43,9 +43,9 @@ public: KYTY_CLASS_NO_COPY(Buffer); [[nodiscard]] vk::Buffer Handle() const noexcept; - [[nodiscard]] uint64_t Size() const noexcept { return m_size; } + [[nodiscard]] uint64_t Size() const noexcept; [[nodiscard]] std::span Mapped() const noexcept { return m_mapped; } - [[nodiscard]] bool IsCoherent() const noexcept { return m_is_coherent; } + [[nodiscard]] bool IsCoherent() const noexcept; [[nodiscard]] MemoryUsage Usage() const noexcept { return m_usage; } [[nodiscard]] uint64_t CpuAddress() const noexcept { return m_cpu_address; } [[nodiscard]] vk::DeviceAddress BufferDeviceAddress() const noexcept; @@ -77,7 +77,6 @@ public: protected: [[nodiscard]] GraphicContext& Graphics() const noexcept { return *m_graphics; } [[nodiscard]] CommandScheduler& Scheduler() const noexcept { return *m_scheduler; } - [[nodiscard]] VulkanBuffer& NativeBuffer() noexcept { return *m_buffer; } private: [[nodiscard]] vk::BufferMemoryBarrier Barrier(uint64_t offset, uint64_t size, @@ -88,11 +87,9 @@ private: CommandScheduler* m_scheduler = nullptr; MemoryUsage m_usage = MemoryUsage::DeviceLocal; uint64_t m_cpu_address = 0; - uint64_t m_size = 0; vk::DeviceAddress m_device_address = 0; std::unique_ptr m_buffer; std::span m_mapped; - bool m_is_coherent = false; }; class StreamBuffer final: public Buffer { @@ -113,7 +110,6 @@ private: uint64_t upper_bound = 0; }; - void ReserveWatches(std::vector& watches, size_t grow_size); [[nodiscard]] static bool NormalizeReservation(bool coherent, uint64_t atom, uint64_t& size, uint64_t& alignment); [[nodiscard]] bool WaitPendingOperations(const std::vector& watches, diff --git a/src/graphics/host_gpu/vma.cpp b/src/graphics/host_gpu/vma.cpp index ec5d5fec4..f9e2a02f8 100644 --- a/src/graphics/host_gpu/vma.cpp +++ b/src/graphics/host_gpu/vma.cpp @@ -35,28 +35,20 @@ struct MemoryStats { MemoryStats g_memory_stats; -void TrackAllocationImpl(const VulkanMemory& memory) { +} // namespace + +void VulkanTrackAllocation(const VulkanMemory& memory) { g_memory_stats.allocated[memory.type] += memory.requirements.size; g_memory_stats.count[memory.type]++; } -void UntrackAllocationImpl(const VulkanMemory& memory) { +void VulkanUntrackAllocation(const VulkanMemory& memory) { EXIT_IF(g_memory_stats.allocated[memory.type] < memory.requirements.size); EXIT_IF(g_memory_stats.count[memory.type] == 0); g_memory_stats.allocated[memory.type] -= memory.requirements.size; g_memory_stats.count[memory.type]--; } -} // namespace - -void VulkanTrackAllocation(const VulkanMemory& memory) { - TrackAllocationImpl(memory); -} - -void VulkanUntrackAllocation(const VulkanMemory& memory) { - UntrackAllocationImpl(memory); -} - bool GraphicContext::CreateAllocator() { KYTY_PROFILER_FUNCTION(); EXIT_IF(instance == nullptr || physical_device == nullptr || device == nullptr || @@ -93,11 +85,6 @@ void GraphicContext::DestroyAllocator() { allocator = nullptr; } -uint64_t VulkanNextMemoryUniqueId() { - static std::atomic_uint64_t sequence = 0; - return ++sequence; -} - void GraphicContext::LogMemoryBudget() const { if (allocator == nullptr || physical_device == nullptr) { return; @@ -166,42 +153,6 @@ uint64_t GraphicContext::GetTotalMemoryBudget() const { return std::max(local, available > system_reserve ? available - system_reserve : uint64_t {0}); } -void GraphicContext::CreateBuffer(uint64_t size, VulkanBuffer& buffer) { - KYTY_PROFILER_FUNCTION(); - EXIT_IF(allocator == nullptr || buffer.buffer != nullptr || - buffer.memory.allocation != nullptr || size == 0); - - vk::BufferCreateInfo buffer_info {}; - buffer_info.sType = vk::StructureType::eBufferCreateInfo; - buffer_info.size = size; - buffer_info.usage = buffer.usage; - buffer_info.sharingMode = vk::SharingMode::eExclusive; - - VmaAllocationCreateInfo alloc_info {}; - alloc_info.requiredFlags = - static_cast(buffer.memory.property); - alloc_info.preferredFlags = - static_cast(buffer.memory.preferred_property); - - vk::Buffer::CType native_buffer = VK_NULL_HANDLE; - const auto result = static_cast(vmaCreateBuffer( - allocator, static_cast(buffer_info), &alloc_info, - &native_buffer, &buffer.memory.allocation, &buffer.memory.allocation_info)); - buffer.buffer = native_buffer; - if (result != vk::Result::eSuccess) { - LogMemoryBudget(); - } - EXIT_NOT_IMPLEMENTED(result != vk::Result::eSuccess); - - device.getBufferMemoryRequirements(buffer.buffer, &buffer.memory.requirements); - buffer.memory.type = buffer.memory.allocation_info.memoryType; - buffer.memory.memory = buffer.memory.allocation_info.deviceMemory; - buffer.memory.offset = buffer.memory.allocation_info.offset; - buffer.memory.unique_id = VulkanNextMemoryUniqueId(); - buffer.buffer_size = size; - VulkanTrackAllocation(buffer.memory); -} - bool GraphicContext::CreateImage(const vk::ImageCreateInfo& image_info, VulkanImage& image) { KYTY_PROFILER_FUNCTION(); EXIT_IF(allocator == nullptr || image.image != nullptr || image.memory.allocation != nullptr); @@ -212,10 +163,11 @@ bool GraphicContext::CreateImage(const vk::ImageCreateInfo& image_info, VulkanIm alloc_info.preferredFlags = static_cast(memory.preferred_property); + VmaAllocationInfo allocation_result {}; vk::Image::CType native_image = VK_NULL_HANDLE; const auto result = static_cast( vmaCreateImage(allocator, static_cast(image_info), - &alloc_info, &native_image, &memory.allocation, &memory.allocation_info)); + &alloc_info, &native_image, &memory.allocation, &allocation_result)); image.image = native_image; if (result != vk::Result::eSuccess) { LogMemoryBudget(); @@ -223,10 +175,7 @@ bool GraphicContext::CreateImage(const vk::ImageCreateInfo& image_info, VulkanIm } device.getImageMemoryRequirements(image.image, &memory.requirements); - memory.type = memory.allocation_info.memoryType; - memory.memory = memory.allocation_info.deviceMemory; - memory.offset = memory.allocation_info.offset; - memory.unique_id = VulkanNextMemoryUniqueId(); + memory.type = allocation_result.memoryType; VulkanTrackAllocation(memory); return true; } @@ -239,23 +188,7 @@ void GraphicContext::DeleteImage(VulkanImage& image) { VulkanUntrackAllocation(memory); vmaDestroyImage(allocator, image.image, memory.allocation); image.image = nullptr; - memory.memory = nullptr; memory.allocation = nullptr; - memory.allocation_info = {}; - memory.offset = 0; -} - -void GraphicContext::MapMemory(VulkanMemory& memory, void*& data) { - KYTY_PROFILER_FUNCTION(); - EXIT_IF(allocator == nullptr || memory.allocation == nullptr); - EXIT_NOT_IMPLEMENTED(static_cast(vmaMapMemory(allocator, memory.allocation, - &data)) != vk::Result::eSuccess); -} - -void GraphicContext::UnmapMemory(VulkanMemory& memory) { - KYTY_PROFILER_FUNCTION(); - EXIT_IF(allocator == nullptr || memory.allocation == nullptr); - vmaUnmapMemory(allocator, memory.allocation); } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/vma.h b/src/graphics/host_gpu/vma.h index a656b676f..f24822284 100644 --- a/src/graphics/host_gpu/vma.h +++ b/src/graphics/host_gpu/vma.h @@ -6,7 +6,6 @@ namespace Libs::Graphics { -uint64_t VulkanNextMemoryUniqueId(); void VulkanTrackAllocation(const VulkanMemory& memory); void VulkanUntrackAllocation(const VulkanMemory& memory); diff --git a/tests/MemoryTrackerTests.cpp b/tests/MemoryTrackerTests.cpp index 96345a431..cf319fab3 100644 --- a/tests/MemoryTrackerTests.cpp +++ b/tests/MemoryTrackerTests.cpp @@ -176,13 +176,10 @@ uint8_t *Allocate(PageManager &manager, uint64_t pages) { VirtualAlloc(reinterpret_cast(base), size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)); Check(memory == reinterpret_cast(base), "fixed VirtualAlloc failed"); - manager.OnGpuMap(base, size); return memory; } -void Release(PageManager &manager, uint8_t *memory, uint64_t size) { - const auto address = reinterpret_cast(memory); - manager.OnGpuUnmap(address, size); +void Release(uint8_t *memory) { Check(VirtualFree(memory, 0, MEM_RELEASE) != 0, "VirtualFree failed"); } @@ -269,7 +266,7 @@ void TestConcurrentRegionPublication() { second.join(); tracker.UntrackMemory(address, page_size); - Release(page_manager, memory, page_size); + Release(memory); Check(cpu_dirty_results.load(std::memory_order_relaxed) == 2, "concurrent region publication lost initial CPU ownership"); } @@ -303,7 +300,7 @@ void TestCpuDirtyUpload() { Check(tracker.IsRegionCpuModified(address, page_size) && IsWritable(memory), "explicit CPU dirtiness did not release write protection"); tracker.UntrackMemory(address, page_size * 2); - Release(page_manager, memory, page_size * 2); + Release(memory); } void TestRangeInvalidation() { @@ -318,7 +315,6 @@ void TestRangeInvalidation() { Check(memory == reinterpret_cast(base), "range invalidation allocation failed"); const auto address = reinterpret_cast(memory); - page_manager.OnGpuMap(address, size); tracker.ForEachUploadRange( address, size, true, [](uint64_t, uint64_t) noexcept {}, @@ -340,7 +336,7 @@ void TestRangeInvalidation() { Check(flushes == 1, "clean range invalidation unnecessarily requested a GPU flush"); tracker.UntrackMemory(address, size); - Release(page_manager, memory, size); + Release(memory); } void TestGpuReacquisitionAfterInvalidation() { @@ -387,7 +383,7 @@ void TestGpuReacquisitionAfterInvalidation() { tracker.UnmarkRegionAsGpuModified(address, page_size); tracker.MarkRegionAsCpuModified(address, page_size); tracker.UntrackMemory(address, page_size); - Release(page_manager, memory, page_size); + Release(memory); } void TestGpuDirtyBits() { @@ -411,7 +407,7 @@ void TestGpuDirtyBits() { "GPU dirty state did not restore write-only tracking"); tracker.MarkRegionAsCpuModified(address, page_size); tracker.UntrackMemory(address, page_size * 2); - Release(page_manager, memory, page_size * 2); + Release(memory); } void TestExactDirtyIntervalsSharingTrackerPage() { @@ -456,7 +452,7 @@ void TestExactDirtyIntervalsSharingTrackerPage() { "draining the final exact interval did not release its tracker page"); tracker.UntrackMemory(address, page_size); - Release(page_manager, memory, page_size); + Release(memory); } void TestGpuDownloadProtectionMirrors() { @@ -529,7 +525,7 @@ void TestGpuDownloadProtectionMirrors() { "CPU-dirty transition did not release only its write watcher"); tracker.UntrackMemory(address, page_size * 4); - Release(page_manager, memory, page_size * 4); + Release(memory); } void TestCrossRegionUpload() { @@ -545,7 +541,6 @@ void TestCrossRegionUpload() { Check(memory == reinterpret_cast(base), "fixed VirtualAlloc failed"); const auto address = reinterpret_cast(memory); const auto boundary = (address + region_size - 1) & ~(region_size - 1); - page_manager.OnGpuMap(address, region_size * 2); uint32_t ranges = 0; tracker.ForEachUploadRange( boundary - page_size, page_size * 2, false, @@ -557,7 +552,7 @@ void TestCrossRegionUpload() { "cross-region upload did not clear and protect both regions"); tracker.MarkRegionAsCpuModified(boundary - page_size, page_size * 2); tracker.UntrackMemory(address, region_size * 2); - Release(page_manager, memory, region_size * 2); + Release(memory); } void TestUploadDoesNotSerializeDisjointRegion() { @@ -607,7 +602,7 @@ void TestUploadDoesNotSerializeDisjointRegion() { tracker.UnmarkRegionAsGpuModified(allocation_base, page_size); tracker.MarkRegionAsCpuModified(allocation_base, page_size); tracker.UntrackMemory(allocation_base, region_size * 2); - Release(page_manager, memory, region_size * 2); + Release(memory); Check(completed_while_upload_blocked && query_result.load(std::memory_order_relaxed), "upload callback serialized an unrelated tracker region"); @@ -663,7 +658,7 @@ void TestDownloadDoesNotSerializeDisjointRegion() { tracker.MarkRegionAsCpuModified(allocation_base, page_size); tracker.MarkRegionAsCpuModified(second_region, page_size); tracker.UntrackMemory(allocation_base, region_size * 2); - Release(page_manager, memory, region_size * 2); + Release(memory); Check(completed_while_download_blocked && both_gpu_owned, "download callback serialized an unrelated tracker region"); } @@ -726,7 +721,7 @@ void TestGpuUnmarkUsesRegionMask() { "cross-region GPU unmark did not use one update per 4 MiB region"); tracker.UntrackMemory(allocation_base, region_size * 2); - Release(page_manager, memory, region_size * 2); + Release(memory); } void TestFullRegionGpuUnmarkBatching() { @@ -767,7 +762,7 @@ void TestFullRegionGpuUnmarkBatching() { "full-region GPU unmark did not use one exact 4 MiB protection request"); tracker.UntrackMemory(allocation_base, region_size * 2); - Release(page_manager, memory, region_size * 2); + Release(memory); } [[noreturn]] void RunDeathCase(const char *name) { diff --git a/tests/PageManagerTests.cpp b/tests/PageManagerTests.cpp index 9a1a0e71c..6c36c65c9 100644 --- a/tests/PageManagerTests.cpp +++ b/tests/PageManagerTests.cpp @@ -162,7 +162,6 @@ void TestWatchAndUnwatch() { auto *memory = Allocate(page_size * 2); const auto address = reinterpret_cast(memory); - manager.OnGpuMap(address, page_size * 2); manager.UpdatePageWatchers(address, page_size); Check(Protection(memory) == PAGE_READONLY && IsWritable(memory + page_size), "write watch installed incorrect protections"); @@ -170,7 +169,6 @@ void TestWatchAndUnwatch() { "watch protection bypassed the address-space owner callback"); manager.UpdatePageWatchers(address, page_size); Check(IsWritable(memory), "write unwatch did not restore access"); - manager.OnGpuUnmap(address, page_size * 2); Check(VirtualFree(memory, 0, MEM_RELEASE) != 0, "VirtualFree failed"); } @@ -180,7 +178,6 @@ void TestSharedWatcherCounts() { auto *memory = Allocate(page_size); const auto address = reinterpret_cast(memory); - manager.OnGpuMap(address, page_size); manager.UpdatePageWatchers(address + 8, 32); manager.UpdatePageWatchers(address + 128, 64); manager.UpdatePageWatchers(address + 8, 32); @@ -188,7 +185,6 @@ void TestSharedWatcherCounts() { "first unwatch released a shared watcher"); manager.UpdatePageWatchers(address + 128, 64); Check(IsWritable(memory), "last unwatch did not restore access"); - manager.OnGpuUnmap(address, page_size); Check(VirtualFree(memory, 0, MEM_RELEASE) != 0, "VirtualFree failed"); } @@ -203,7 +199,6 @@ void TestCrossRegionRange() { boundary + page_size <= base + region_size * 2, "test allocation does not contain a region boundary"); - manager.OnGpuMap(base, region_size * 2); g_protection_calls = 0; g_protection_ranges.clear(); manager.UpdatePageWatchers(boundary - page_size, page_size * 2); @@ -228,7 +223,6 @@ void TestCrossRegionRange() { Check(IsWritable(reinterpret_cast(boundary - page_size)) && IsWritable(reinterpret_cast(boundary)), "cross-region unwatch did not restore both pages"); - manager.OnGpuUnmap(base, region_size * 2); Check(VirtualFree(memory, 0, MEM_RELEASE) != 0, "VirtualFree failed"); } @@ -240,7 +234,6 @@ void TestBatchedWatcherRanges() { auto *memory = Allocate(allocation_size); const auto address = reinterpret_cast(memory); - manager.OnGpuMap(address, allocation_size); manager.UpdatePageWatchers(address + page_size, page_size); manager.UpdatePageWatchers(address + page_size * 3, page_size); manager.UpdatePageWatchers(address, page_size * 5); @@ -266,7 +259,6 @@ void TestBatchedWatcherRanges() { IsWritable(memory + allocation_size - page_size), "large cross-region unwatch did not restore the full range"); - manager.OnGpuUnmap(address, allocation_size); Check(VirtualFree(memory, 0, MEM_RELEASE) != 0, "VirtualFree failed"); } @@ -280,7 +272,6 @@ void TestRegionMaskWatcherRanges() { (allocation_base + region_size - 1) & ~(region_size - 1); Check(region_base + region_size <= allocation_base + region_size * 2, "test allocation does not contain a complete tracking region"); - manager.OnGpuMap(allocation_base, region_size * 2); RegionBits full_mask; full_mask.Fill(); @@ -364,7 +355,6 @@ void TestRegionMaskWatcherRanges() { g_protection_ranges[0].size == page_size * 3, "sparse read unmask did not bridge a compatible gap"); - manager.OnGpuUnmap(allocation_base, region_size * 2); Check(VirtualFree(memory, 0, MEM_RELEASE) != 0, "VirtualFree failed"); } @@ -379,7 +369,6 @@ void TestRegionEndpointBatching() { (allocation_base + region_size - 1) & ~(region_size - 1); Check(region_base + region_size <= allocation_base + region_size * 2, "test allocation does not contain a complete tracking region"); - manager.OnGpuMap(allocation_base, region_size * 2); RegionBits endpoints; endpoints.Set(0); @@ -420,7 +409,6 @@ void TestRegionEndpointBatching() { g_protection_ranges[0].size == region_size, "last full-region unwatch did not use one 4 MiB protection call"); - manager.OnGpuUnmap(allocation_base, region_size * 2); Check(VirtualFree(memory, 0, MEM_RELEASE) != 0, "VirtualFree failed"); } @@ -434,7 +422,6 @@ void TestReadWriteWatcherInteractions() { (allocation_base + region_size - 1) & ~(region_size - 1); Check(region_base + region_size <= allocation_base + region_size * 2, "test allocation does not contain a complete tracking region"); - manager.OnGpuMap(allocation_base, region_size * 2); RegionBits write_mask; write_mask.SetRange(10, 15); @@ -488,7 +475,6 @@ void TestReadWriteWatcherInteractions() { IsWritable(reinterpret_cast(region_base + page_size * 13)), "read unwatch did not coalesce through compatible writable state"); - manager.OnGpuUnmap(allocation_base, region_size * 2); Check(VirtualFree(memory, 0, MEM_RELEASE) != 0, "VirtualFree failed"); } @@ -503,20 +489,17 @@ void TestReadWriteWatcherInteractions() { auto doomed = std::make_unique(); auto *memory = Allocate(page_size); const auto address = reinterpret_cast(memory); - doomed->OnGpuMap(address, page_size); doomed->UpdatePageWatchers(address, page_size); doomed.reset(); } else if (std::strcmp(name, "known-write-underflow") == 0) { auto *memory = Allocate(page_size); const auto address = reinterpret_cast(memory); - manager.OnGpuMap(address, page_size); manager.UpdatePageWatchers(address, page_size); manager.UpdatePageWatchers(address, page_size); manager.UpdatePageWatchers(address, page_size); } else if (std::strcmp(name, "read-overflow") == 0) { auto *memory = Allocate(page_size); const auto address = reinterpret_cast(memory); - manager.OnGpuMap(address, page_size); RegionBits mask; const auto region_base = address & ~(TRACKER_REGION_SIZE - 1); const auto page = static_cast((address - region_base) / page_size); @@ -526,7 +509,6 @@ void TestReadWriteWatcherInteractions() { } else if (std::strcmp(name, "write-overflow") == 0) { auto *memory = Allocate(page_size); const auto address = reinterpret_cast(memory); - manager.OnGpuMap(address, page_size); for (uint32_t count = 0; count < 128; count++) { manager.UpdatePageWatchers(address, page_size); } diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 065024712..5a7a95b73 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -25536,7 +25536,6 @@ void CheckStorageTextureGpuOwnedRebindState() { "fixed guest-owner allocation failed"); PageManager page_manager; MemoryTracker tracker(page_manager); - page_manager.OnGpuMap(base, size); tracker.ForEachUploadRange( base, size, true, [](uint64_t, uint64_t) noexcept {}, []() noexcept {}); uint64_t readable = 0; @@ -25588,7 +25587,6 @@ void CheckStorageTextureGpuOwnedRebindState() { tracker.UnmarkRegionAsGpuModified(base, size); tracker.UntrackMemory(base, size); - page_manager.OnGpuUnmap(base, size); Require("StorageTextureGpuOwnedRebind", "free", Libs::LibKernel::Memory::FreeGuestMemory(base, size), "guest-owner free failed");