Publish synchronous buffer downloads inline after ordered completion

This commit is contained in:
nmzik
2026-10-02 13:00:47 +04:00
parent a67a033ff8
commit 39e23ac92e
3 changed files with 42 additions and 11 deletions
+14 -8
View File
@@ -110,6 +110,7 @@ void BufferCache::DeleteBuffer(BufferId id) {
}
}
template <bool async>
bool BufferCache::DownloadBufferMemory(Buffer& buffer, uint64_t vaddr, uint64_t size) {
std::vector<vk::BufferCopy> copies;
uint64_t total_size = 0;
@@ -170,14 +171,22 @@ bool BufferCache::DownloadBufferMemory(Buffer& buffer, uint64_t vaddr, uint64_t
vk::PipelineStageFlagBits::eAllCommands |
vk::PipelineStageFlagBits::eHost,
{}, 0, nullptr, 1, &after, 0, nullptr);
m_scheduler.DeferPriorityOperation([this, mapped, offset, total_size, buffer_address,
copies = std::move(copies), owner = std::move(temporary)] {
auto publish = [this, mapped, offset, total_size, buffer_address,
copies = std::move(copies), owner = std::move(temporary)] {
(owner ? *owner : m_download_buffer).Invalidate(offset, total_size);
for (const auto& copy: copies) {
Libs::LibKernel::Memory::WriteBacking(buffer_address + copy.srcOffset,
mapped + (copy.dstOffset - offset), copy.size);
}
});
};
if constexpr (async) {
m_scheduler.DeferPriorityOperation(std::move(publish));
} else {
const auto tick = m_scheduler.CurrentTick();
m_scheduler.Wait(tick);
m_scheduler.WaitPriorityOperations(tick);
publish();
}
return true;
}
@@ -256,10 +265,7 @@ void BufferCache::ReadMemory(uint64_t vaddr, uint64_t size, bool is_write) {
const auto window_begin = std::max(Common::AlignDown(vaddr, WindowSize), buffer_begin);
const auto window_end = std::min(std::max(window_begin + WindowSize, vaddr + size), buffer_end);
if (DownloadBufferMemory(buffer, window_begin, window_end - window_begin)) {
const auto tick = m_scheduler.CurrentTick();
m_scheduler.Wait(tick);
m_scheduler.WaitPriorityOperations(tick);
if (DownloadBufferMemory<false>(buffer, window_begin, window_end - window_begin)) {
m_memory_tracker.UnmarkRegionAsGpuModified(window_begin, window_end - window_begin);
}
if (is_write) {
@@ -614,7 +620,7 @@ void BufferCache::RunGarbageCollector() {
return false;
}
if (dirty) {
EXIT_IF(!DownloadBufferMemory(buffer, buffer.CpuAddress(), buffer.Size()));
EXIT_NOT_IMPLEMENTED(!DownloadBufferMemory<true>(buffer, buffer.CpuAddress(), buffer.Size()));
dirty_buffers.push_back(id);
} else {
m_memory_tracker.UntrackMemory(buffer.CpuAddress(), buffer.Size());
+2 -1
View File
@@ -117,7 +117,8 @@ private:
[[nodiscard]] vk::Buffer UploadCopies(Buffer& buffer, std::span<vk::BufferCopy> copies,
uint64_t total_size);
[[nodiscard]] bool SynchronizeBufferFromImage(Buffer& buffer, uint64_t vaddr, uint64_t size);
// Queues backing publication; callers wait before clearing dirty pages or reusing their data.
// Synchronous downloads publish before returning; asynchronous callers wait before reuse.
template <bool async>
[[nodiscard]] bool DownloadBufferMemory(Buffer& buffer, uint64_t vaddr, uint64_t size);
GraphicContext& m_graphics;
+26 -2
View File
@@ -4208,7 +4208,30 @@ public:
cache.FillBuffer(base + offset, sizeof(window_value), window_value,
false);
}
const auto window_publication_tick = scheduler.CurrentTick();
std::binary_semaphore window_publication_entered{0};
std::binary_semaphore release_window_publication{0};
std::atomic<bool> window_readback_returned{false};
scheduler.DeferPriorityOperation([&] {
window_publication_entered.release();
release_window_publication.acquire();
Libs::LibKernel::Memory::WriteBacking(
base + window_inside_offset, &window_stale, sizeof(window_stale));
});
std::jthread release_window_callback([&] {
window_publication_entered.acquire();
const auto deadline = std::chrono::steady_clock::now() +
std::chrono::milliseconds(100);
while (!window_readback_returned.load() &&
std::chrono::steady_clock::now() < deadline) {
std::this_thread::yield();
}
release_window_publication.release();
});
cache.ReadMemory(base + window_fault_offset, sizeof(window_value));
window_readback_returned = true;
release_window_callback.join();
scheduler.WaitPriorityOperations(window_publication_tick);
uint32_t window_inside_backing = 0;
uint32_t window_outside_backing = 0;
Libs::LibKernel::Memory::TryReadBacking(base + window_inside_offset,
@@ -4217,7 +4240,7 @@ public:
Libs::LibKernel::Memory::TryReadBacking(base + window_outside_offset,
&window_outside_backing,
sizeof(window_outside_backing));
Require(name, "widened-window boundary",
Require(name, "widened-window publication order and boundary",
window_inside_backing == window_value &&
window_outside_backing == window_stale &&
!cache.HasGpuDirtyBytes(base + window_inside_offset,
@@ -4228,7 +4251,8 @@ public:
sizeof(window_value)) &&
cache.IsRegionGpuModified(base + window_outside_offset,
sizeof(window_value)),
"readback did not honor the clamped half-open 512 KiB window");
"readback did not publish after the older overlapping callback "
"or honor the clamped half-open 512 KiB window");
cache.ReadMemory(base + window_outside_offset, sizeof(window_value));
Libs::LibKernel::Memory::WriteBacking(base + first_offset, &first_stale,