textures: keep dirty pages during image-to-buffer sync

This commit is contained in:
nmzik
2026-09-06 05:36:41 +04:00
parent 803c124136
commit 98e7eeb72a
2 changed files with 25 additions and 59 deletions
+10 -54
View File
@@ -501,37 +501,18 @@ std::pair<Buffer*, uint64_t> BufferCache::ObtainBufferForImage(uint64_t vaddr, u
if (!GuestRange {vaddr, size}.Valid()) {
EXIT("BufferCache: invalid image source\n");
}
auto find_owner = [&]() -> Buffer* {
const auto* owner = m_page_table.Find(vaddr >> PageTable::kPageBits);
if (owner == nullptr || !*owner) {
return nullptr;
}
const auto* owner = m_page_table.Find(vaddr >> PageTable::kPageBits);
if (owner != nullptr && *owner) {
auto& buffer = m_slot_buffers[*owner];
return buffer.IsInBounds(vaddr, size) ? &buffer : nullptr;
};
{
const bool cpu_modified = m_memory_tracker.IsRegionCpuModified(vaddr, size);
const bool gpu_modified = m_memory_tracker.IsRegionGpuModified(vaddr, size);
const bool has_dirty_buffer_source = m_gpu_modified_ranges.Intersects(vaddr, size);
m_memory_tracker.ValidateGpuDirtyOwnership(m_gpu_modified_ranges, vaddr, size,
"image source");
auto* owner = find_owner();
if (has_dirty_buffer_source && owner == nullptr) {
if (!IsRegionRegistered(vaddr, size)) {
EXIT("BufferCache: GPU-dirty image source has no native buffer\n");
}
owner = &m_slot_buffers[FindBuffer(vaddr, size)];
}
if (owner != nullptr && !cpu_modified && (!gpu_modified || has_dirty_buffer_source)) {
TouchBuffer(*owner);
return {owner, owner->Offset(vaddr)};
}
if (has_dirty_buffer_source && owner == nullptr) {
EXIT("BufferCache: GPU-dirty image source could not resolve its native owner\n");
if (buffer.IsInBounds(vaddr, size)) {
TouchBuffer(buffer);
(void)SynchronizeBuffer(buffer, vaddr, size, false, false);
return {&buffer, buffer.Offset(vaddr)};
}
}
if (IsRegionGpuModified(vaddr, size)) {
return ObtainBuffer(vaddr, size, false, false);
}
auto [staging, stage_offset] = m_staging_buffer.Map(size, 16);
if (staging == nullptr || (!Libs::LibKernel::Memory::TryReadBacking(vaddr, staging, size) &&
@@ -539,32 +520,7 @@ std::pair<Buffer*, uint64_t> BufferCache::ObtainBufferForImage(uint64_t vaddr, u
EXIT("BufferCache: failed to read mapped guest image backing\n");
}
m_staging_buffer.Commit();
const bool has_dirty_buffer_source = m_gpu_modified_ranges.Intersects(vaddr, size);
auto* owner = find_owner();
if (has_dirty_buffer_source && owner == nullptr) {
EXIT("BufferCache: GPU-dirty image source lost its native owner\n");
}
if (owner == nullptr ||
(m_memory_tracker.IsRegionGpuModified(vaddr, size) && !has_dirty_buffer_source)) {
return {&m_staging_buffer, stage_offset};
}
TouchBuffer(*owner);
std::vector<std::pair<uint64_t, uint64_t>> uploads;
m_memory_tracker.ForEachUploadRange(
vaddr, size, false,
[&](uint64_t address, uint64_t upload_size) noexcept {
uploads.emplace_back(address, upload_size);
},
[&]() noexcept {
for (const auto& [address, upload_size]: uploads) {
owner->CopyFrom(m_scheduler.Current(), m_staging_buffer,
stage_offset + address - vaddr, owner->Offset(address), upload_size,
vk::AccessFlagBits::eHostWrite);
}
});
return {owner, owner->Offset(vaddr)};
return {&m_staging_buffer, stage_offset};
}
void BufferCache::WriteHostMemory(uint64_t vaddr, std::span<const uint8_t> data) {
+15 -5
View File
@@ -5585,6 +5585,15 @@ public:
"same-page CPU write did not invalidate cached ownership");
std::memcpy(memory + partial_clean_offset, &partial_cpu_refresh_value,
sizeof(partial_cpu_refresh_value));
constexpr std::array<uint32_t, 2> partial_neighbors{0x2468ace0u,
0xfedcba98u};
std::memcpy(memory + partial_clean_offset - sizeof(uint32_t),
&partial_neighbors[0], sizeof(uint32_t));
std::memcpy(memory + partial_clean_offset + sizeof(uint32_t),
&partial_neighbors[1], sizeof(uint32_t));
std::vector<u32> partial_cpu_refresh_expected(TRACKER_PAGE_SIZE / sizeof(u32));
std::memcpy(partial_cpu_refresh_expected.data(), memory + partial_image_offset,
TRACKER_PAGE_SIZE);
const auto partial_cpu_refresh_source =
resources.GetBufferCache().ObtainBufferForImage(
base + partial_clean_offset, sizeof(partial_cpu_refresh_value));
@@ -5593,11 +5602,11 @@ public:
"CPU-dirty same-page bytes did not resolve through the cached "
"buffer");
auto partial_cpu_refresh_readback =
CreateHostBuffer(name, sizeof(partial_cpu_refresh_value),
CreateHostBuffer(name, TRACKER_PAGE_SIZE,
vk::BufferUsageFlagBits::eTransferDst, {0});
const vk::BufferCopy partial_cpu_refresh_copy{
partial_cpu_refresh_source.second, 0,
sizeof(partial_cpu_refresh_value)};
partial_cpu_refresh_source.first->Offset(base + partial_image_offset), 0,
TRACKER_PAGE_SIZE};
command.Handle().copyBuffer(partial_cpu_refresh_source.first->Handle(),
partial_cpu_refresh_readback.buffer, 1,
&partial_cpu_refresh_copy);
@@ -6443,8 +6452,9 @@ public:
"exact-format recreation initialized from "
"stale guest bytes");
Require(name, "partial-page CPU refresh content",
ReadBuffer(name, partial_cpu_refresh_readback, 1) ==
std::vector<u32>{partial_cpu_refresh_value},
ReadBuffer(name, partial_cpu_refresh_readback,
partial_cpu_refresh_expected.size()) ==
partial_cpu_refresh_expected,
"cached buffer uploaded bytes outside the exact "
"staged guest range");
const auto mixed_source_words = ReadBuffer(