untrack only first page of the image in case of head access

This commit is contained in:
Vladislav Mikhalin 2024-11-24 22:37:54 +03:00
parent 7936dd7386
commit da28623315
5 changed files with 70 additions and 6 deletions

View File

@ -114,7 +114,7 @@ struct PageManager::Impl {
// Notify rasterizer about the fault. // Notify rasterizer about the fault.
const VAddr addr = msg.arg.pagefault.address; const VAddr addr = msg.arg.pagefault.address;
const VAddr addr_page = Common::AlignDown(addr, PAGESIZE); const VAddr addr_page = GetPageAddr(addr);
rasterizer->InvalidateMemory(addr, addr_page, PAGESIZE); rasterizer->InvalidateMemory(addr, addr_page, PAGESIZE);
} }
} }
@ -157,7 +157,7 @@ struct PageManager::Impl {
const auto addr = reinterpret_cast<VAddr>(fault_address); const auto addr = reinterpret_cast<VAddr>(fault_address);
const bool is_write = Common::IsWriteError(context); const bool is_write = Common::IsWriteError(context);
if (is_write && owned_ranges.find(addr) != owned_ranges.end()) { if (is_write && owned_ranges.find(addr) != owned_ranges.end()) {
const VAddr addr_aligned = Common::AlignDown(addr, PAGESIZE); const VAddr addr_aligned = GetPageAddr(addr);
rasterizer->InvalidateMemory(addr, addr_aligned, PAGESIZE); rasterizer->InvalidateMemory(addr, addr_aligned, PAGESIZE);
return true; return true;
} }
@ -174,6 +174,14 @@ PageManager::PageManager(Vulkan::Rasterizer* rasterizer_)
PageManager::~PageManager() = default; PageManager::~PageManager() = default;
VAddr PageManager::GetPageAddr(VAddr addr) {
return Common::AlignDown(addr, PAGESIZE);
}
VAddr PageManager::GetNextPageAddr(VAddr addr) {
return Common::AlignUp(addr + 1, PAGESIZE);
}
void PageManager::OnGpuMap(VAddr address, size_t size) { void PageManager::OnGpuMap(VAddr address, size_t size) {
impl->OnMap(address, size); impl->OnMap(address, size);
} }

View File

@ -28,6 +28,9 @@ public:
/// Increase/decrease the number of surface in pages touching the specified region /// Increase/decrease the number of surface in pages touching the specified region
void UpdatePagesCachedCount(VAddr addr, u64 size, s32 delta); void UpdatePagesCachedCount(VAddr addr, u64 size, s32 delta);
static VAddr GetPageAddr(VAddr addr);
static VAddr GetNextPageAddr(VAddr addr);
private: private:
struct Impl; struct Impl;
std::unique_ptr<Impl> impl; std::unique_ptr<Impl> impl;

View File

@ -25,9 +25,10 @@ enum ImageFlagBits : u32 {
MaybeCpuDirty = 1 << 0, ///< The page this image is in was touched before the image address MaybeCpuDirty = 1 << 0, ///< The page this image is in was touched before the image address
CpuDirty = 1 << 1, ///< Contents have been modified from the CPU CpuDirty = 1 << 1, ///< Contents have been modified from the CPU
GpuDirty = 1 << 2, ///< Contents have been modified from the GPU (valid data in buffer cache) GpuDirty = 1 << 2, ///< Contents have been modified from the GPU (valid data in buffer cache)
Dirty = CpuDirty | GpuDirty | MaybeCpuDirty, Dirty = MaybeCpuDirty | CpuDirty | GpuDirty,
GpuModified = 1 << 3, ///< Contents have been modified from the GPU GpuModified = 1 << 3, ///< Contents have been modified from the GPU
Tracked = 1 << 4, ///< Writes and reads are being hooked from the CPU Tracked = 1 << 4, ///< Writes and reads are being hooked from the CPU
TailTracked = 1 << 5, ///< Writes and reads to the image tail are being hooked from the CPU
Registered = 1 << 6, ///< True when the image is registered Registered = 1 << 6, ///< True when the image is registered
Picked = 1 << 7, ///< Temporary flag to mark the image as picked Picked = 1 << 7, ///< Temporary flag to mark the image as picked
MetaRegistered = 1 << 8, ///< True when metadata for this surface is known and registered MetaRegistered = 1 << 8, ///< True when metadata for this surface is known and registered

View File

@ -56,8 +56,15 @@ void TextureCache::InvalidateMemory(VAddr addr, VAddr addr_aligned, size_t size)
// Image ends on this page so it can not receive any more invalidations. // Image ends on this page so it can not receive any more invalidations.
// We will check it's hash later to see if it really was modified. // We will check it's hash later to see if it really was modified.
image.flags |= ImageFlagBits::MaybeCpuDirty; image.flags |= ImageFlagBits::MaybeCpuDirty;
UntrackImage(image_id);
} else {
// Remove tracking from this page only.
UntrackImageHead(image_id);
} }
} else if (addr < image_end) { return;
}
if (addr < image_end) {
// Ensure image is reuploaded when accessed again. // Ensure image is reuploaded when accessed again.
image.flags |= ImageFlagBits::CpuDirty; image.flags |= ImageFlagBits::CpuDirty;
} }
@ -436,6 +443,7 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
const u8* addr = std::bit_cast<u8*>(image.info.guest_address); const u8* addr = std::bit_cast<u8*>(image.info.guest_address);
const u64 hash = XXH3_64bits(addr, image.info.guest_size_bytes); const u64 hash = XXH3_64bits(addr, image.info.guest_size_bytes);
if (image.hash == hash) { if (image.hash == hash) {
image.flags &= ~ImageFlagBits::MaybeCpuDirty;
return; return;
} }
image.hash = hash; image.hash = hash;
@ -481,6 +489,7 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
} }
if (image_copy.empty()) { if (image_copy.empty()) {
image.flags &= ~ImageFlagBits::Dirty;
return; return;
} }
@ -556,22 +565,59 @@ void TextureCache::TrackImage(ImageId image_id) {
if (True(image.flags & ImageFlagBits::Tracked)) { if (True(image.flags & ImageFlagBits::Tracked)) {
return; return;
} }
if (True(image.flags & ImageFlagBits::TailTracked)) {
// Re-track only image head
TrackImageHead(image_id);
} else {
// Re-track the whole image
image.flags |= ImageFlagBits::Tracked;
tracker.UpdatePagesCachedCount(image.cpu_addr, image.info.guest_size_bytes, 1);
}
}
void TextureCache::TrackImageHead(ImageId image_id) {
auto& image = slot_images[image_id];
if (True(image.flags & ImageFlagBits::Tracked)) {
return;
}
ASSERT(True(image.flags & ImageFlagBits::TailTracked));
image.flags |= ImageFlagBits::Tracked; image.flags |= ImageFlagBits::Tracked;
tracker.UpdatePagesCachedCount(image.cpu_addr, image.info.guest_size_bytes, 1); image.flags &= ~ImageFlagBits::TailTracked;
const auto size = tracker.GetNextPageAddr(image.cpu_addr) - image.cpu_addr;
tracker.UpdatePagesCachedCount(image.cpu_addr, size, 1);
} }
void TextureCache::UntrackImage(ImageId image_id) { void TextureCache::UntrackImage(ImageId image_id) {
auto& image = slot_images[image_id];
ASSERT(!True(image.flags & ImageFlagBits::Tracked) ||
!True(image.flags & ImageFlagBits::TailTracked));
if (True(image.flags & ImageFlagBits::Tracked)) {
image.flags &= ~ImageFlagBits::Tracked;
tracker.UpdatePagesCachedCount(image.cpu_addr, image.info.guest_size_bytes, -1);
}
if (True(image.flags & ImageFlagBits::TailTracked)) {
image.flags &= ~ImageFlagBits::TailTracked;
const auto addr = tracker.GetNextPageAddr(image.cpu_addr);
const auto size = image.info.guest_size_bytes - (addr - image.cpu_addr);
tracker.UpdatePagesCachedCount(addr, size, -1);
}
}
void TextureCache::UntrackImageHead(ImageId image_id) {
auto& image = slot_images[image_id]; auto& image = slot_images[image_id];
if (False(image.flags & ImageFlagBits::Tracked)) { if (False(image.flags & ImageFlagBits::Tracked)) {
return; return;
} }
image.flags |= ImageFlagBits::TailTracked;
image.flags &= ~ImageFlagBits::Tracked; image.flags &= ~ImageFlagBits::Tracked;
tracker.UpdatePagesCachedCount(image.cpu_addr, image.info.guest_size_bytes, -1); const auto size = tracker.GetNextPageAddr(image.cpu_addr) - image.cpu_addr;
tracker.UpdatePagesCachedCount(image.cpu_addr, size, -1);
} }
void TextureCache::DeleteImage(ImageId image_id) { void TextureCache::DeleteImage(ImageId image_id) {
Image& image = slot_images[image_id]; Image& image = slot_images[image_id];
ASSERT_MSG(False(image.flags & ImageFlagBits::Tracked), "Image was not untracked"); ASSERT_MSG(False(image.flags & ImageFlagBits::Tracked), "Image was not untracked");
ASSERT_MSG(False(image.flags & ImageFlagBits::TailTracked), "Image was not untracked");
ASSERT_MSG(False(image.flags & ImageFlagBits::Registered), "Image was not unregistered"); ASSERT_MSG(False(image.flags & ImageFlagBits::Registered), "Image was not unregistered");
// Remove any registered meta areas. // Remove any registered meta areas.

View File

@ -243,9 +243,15 @@ private:
/// Track CPU reads and writes for image /// Track CPU reads and writes for image
void TrackImage(ImageId image_id); void TrackImage(ImageId image_id);
/// Track CPU reads and writes for image
void TrackImageHead(ImageId image_id);
/// Stop tracking CPU reads and writes for image /// Stop tracking CPU reads and writes for image
void UntrackImage(ImageId image_id); void UntrackImage(ImageId image_id);
/// Stop tracking CPU reads and writes for the first page of the image
void UntrackImageHead(ImageId image_id);
/// Removes the image and any views/surface metas that reference it. /// Removes the image and any views/surface metas that reference it.
void DeleteImage(ImageId image_id); void DeleteImage(ImageId image_id);