Skip to content

Commit

Permalink
untrack only first page of the image in case of head access
Browse files Browse the repository at this point in the history
  • Loading branch information
roamic authored and ngoquang2708 committed Nov 25, 2024
1 parent 9e03718 commit 75af602
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 6 deletions.
12 changes: 10 additions & 2 deletions src/video_core/page_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ struct PageManager::Impl {

// Notify rasterizer about the fault.
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);
}
}
Expand Down Expand Up @@ -157,7 +157,7 @@ struct PageManager::Impl {
const auto addr = reinterpret_cast<VAddr>(fault_address);
const bool is_write = Common::IsWriteError(context);
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);
return true;
}
Expand All @@ -174,6 +174,14 @@ PageManager::PageManager(Vulkan::Rasterizer* rasterizer_)

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) {
impl->OnMap(address, size);
}
Expand Down
3 changes: 3 additions & 0 deletions src/video_core/page_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ class PageManager {
/// Increase/decrease the number of surface in pages touching the specified region
void UpdatePagesCachedCount(VAddr addr, u64 size, s32 delta);

static VAddr GetPageAddr(VAddr addr);
static VAddr GetNextPageAddr(VAddr addr);

private:
struct Impl;
std::unique_ptr<Impl> impl;
Expand Down
3 changes: 2 additions & 1 deletion src/video_core/texture_cache/image.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ enum ImageFlagBits : u32 {
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
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
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
Picked = 1 << 7, ///< Temporary flag to mark the image as picked
MetaRegistered = 1 << 8, ///< True when metadata for this surface is known and registered
Expand Down
52 changes: 49 additions & 3 deletions src/video_core/texture_cache/texture_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
// We will check it's hash later to see if it really was modified.
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.
image.flags |= ImageFlagBits::CpuDirty;
}
Expand Down Expand Up @@ -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 u64 hash = XXH3_64bits(addr, image.info.guest_size_bytes);
if (image.hash == hash) {
image.flags &= ~ImageFlagBits::MaybeCpuDirty;
return;
}
image.hash = hash;
Expand Down Expand Up @@ -481,6 +489,7 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
}

if (image_copy.empty()) {
image.flags &= ~ImageFlagBits::Dirty;
return;
}

Expand Down Expand Up @@ -556,22 +565,59 @@ void TextureCache::TrackImage(ImageId image_id) {
if (True(image.flags & ImageFlagBits::Tracked)) {
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;
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) {
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];
if (False(image.flags & ImageFlagBits::Tracked)) {
return;
}
image.flags |= ImageFlagBits::TailTracked;
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) {
Image& image = slot_images[image_id];
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");

// Remove any registered meta areas.
Expand Down
6 changes: 6 additions & 0 deletions src/video_core/texture_cache/texture_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,15 @@ class TextureCache {
/// Track CPU reads and writes for image
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
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.
void DeleteImage(ImageId image_id);

Expand Down

0 comments on commit 75af602

Please sign in to comment.