render: simplify buffer and memory tracking ownership

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