Skip to content

Commit c24476c

Browse files
committed
include image tail in the calculations
1 parent ec10c5d commit c24476c

File tree

5 files changed

+140
-74
lines changed

5 files changed

+140
-74
lines changed

src/video_core/buffer_cache/buffer_cache.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ bool BufferCache::SynchronizeBufferFromImage(Buffer& buffer, VAddr device_addr,
635635
"Texel buffer aliases image subresources {:x} : {:x}", device_addr,
636636
image.info.guest_address);
637637
boost::container::small_vector<vk::BufferImageCopy, 8> copies;
638-
u32 offset = buffer.Offset(image.cpu_addr);
638+
u32 offset = buffer.Offset(image.info.guest_address);
639639
const u32 num_layers = image.info.resources.layers;
640640
const u32 max_offset = offset + size;
641641
for (u32 m = 0; m < image.info.resources.levels; m++) {

src/video_core/texture_cache/image.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,7 @@ void UniqueImage::Create(const vk::ImageCreateInfo& image_ci) {
144144
Image::Image(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_,
145145
const ImageInfo& info_)
146146
: instance{&instance_}, scheduler{&scheduler_}, info{info_},
147-
image{instance->GetDevice(), instance->GetAllocator()}, cpu_addr{info.guest_address},
148-
cpu_addr_end{cpu_addr + info.guest_size_bytes} {
147+
image{instance->GetDevice(), instance->GetAllocator()} {
149148
mip_hashes.resize(info.resources.levels);
150149
ASSERT(info.pixel_format != vk::Format::eUndefined);
151150
// Here we force `eExtendedUsage` as don't know all image usage cases beforehand. In normal case

src/video_core/texture_cache/image.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,12 @@ VK_DEFINE_HANDLE(VmaAllocator)
2222
namespace VideoCore {
2323

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

8180
[[nodiscard]] bool Overlaps(VAddr overlap_cpu_addr, size_t overlap_size) const noexcept {
8281
const VAddr overlap_end = overlap_cpu_addr + overlap_size;
83-
return cpu_addr < overlap_end && overlap_cpu_addr < cpu_addr_end;
82+
const auto image_addr = info.guest_address;
83+
const auto image_end = info.guest_address + info.guest_size_bytes;
84+
return image_addr < overlap_end && overlap_cpu_addr < image_end;
8485
}
8586

8687
ImageViewId FindView(const ImageViewInfo& info) const {
@@ -101,14 +102,18 @@ struct Image {
101102
void CopyImage(const Image& image);
102103
void CopyMip(const Image& image, u32 mip);
103104

105+
bool IsTracked() {
106+
return track_addr != 0 && track_addr_end != 0;
107+
}
108+
104109
const Vulkan::Instance* instance;
105110
Vulkan::Scheduler* scheduler;
106111
ImageInfo info;
107112
UniqueImage image;
108113
vk::ImageAspectFlags aspect_mask = vk::ImageAspectFlagBits::eColor;
109114
ImageFlagBits flags = ImageFlagBits::Dirty;
110-
VAddr cpu_addr = 0;
111-
VAddr cpu_addr_end = 0;
115+
VAddr track_addr = 0;
116+
VAddr track_addr_end = 0;
112117
std::vector<ImageViewInfo> image_view_infos;
113118
std::vector<ImageViewId> image_view_ids;
114119

src/video_core/texture_cache/texture_cache.cpp

Lines changed: 124 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,12 @@ TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler&
2929
info.UpdateSize();
3030
const ImageId null_id = slot_images.insert(instance, scheduler, info);
3131
ASSERT(null_id.index == NULL_IMAGE_ID.index);
32-
const vk::Image& null_image = slot_images[null_id].image;
32+
auto& img = slot_images[null_id];
33+
const vk::Image& null_image = img.image;
3334
Vulkan::SetObjectName(instance.GetDevice(), null_image, "Null Image");
34-
slot_images[null_id].flags = ImageFlagBits::Tracked;
35+
img.flags = ImageFlagBits::Empty;
36+
img.track_addr = img.info.guest_address;
37+
img.track_addr_end = img.info.guest_address + img.info.guest_size_bytes;
3538

3639
ImageViewInfo view_info;
3740
const auto null_view_id =
@@ -43,37 +46,49 @@ TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler&
4346

4447
TextureCache::~TextureCache() = default;
4548

49+
void TextureCache::MarkAsMaybeDirty(ImageId image_id, Image& image) {
50+
if (image.hash == 0) {
51+
// Initialize hash
52+
const u8* addr = std::bit_cast<u8*>(image.info.guest_address);
53+
image.hash = XXH3_64bits(addr, image.info.guest_size_bytes);
54+
}
55+
image.flags |= ImageFlagBits::MaybeCpuDirty;
56+
UntrackImage(image_id);
57+
}
58+
4659
void TextureCache::InvalidateMemory(VAddr addr, VAddr page_addr, size_t size) {
4760
std::scoped_lock lock{mutex};
4861
ForEachImageInRegion(page_addr, size, [&](ImageId image_id, Image& image) {
49-
if (addr < image.cpu_addr) {
62+
const auto image_begin = image.info.guest_address;
63+
const auto image_end = image.info.guest_address + image.info.guest_size_bytes;
64+
const auto page_end = page_addr + size;
65+
if (image_begin <= addr && addr < image_end) {
66+
// This image was definitely accessed by this page fault.
67+
// Untrack image, so the range is unprotected and the guest can write freely
68+
image.flags |= ImageFlagBits::CpuDirty;
69+
UntrackImage(image_id);
70+
} else if (page_end < image_end) {
5071
// This page access may or may not modify the image.
51-
// We should not mark it as dirty now, if it really was modified,
52-
// it will receive more invalidations on subsequent pages.
53-
const auto page_end = page_addr + size;
54-
if (image.cpu_addr_end <= page_end) {
55-
if (image.hash == 0) {
56-
// Initialize hash
57-
const u8* addr = std::bit_cast<u8*>(image.info.guest_address);
58-
image.hash = XXH3_64bits(addr, image.info.guest_size_bytes);
59-
}
60-
// Image ends on this page so it can not receive any more invalidations.
61-
// We will check it's hash later to see if it really was modified.
62-
image.flags |= ImageFlagBits::MaybeCpuDirty;
63-
UntrackImage(image_id);
64-
} else {
65-
// Remove tracking from this page only.
66-
UntrackImageHead(image_id);
72+
// We should not mark it as dirty now. If it really was modified
73+
// it will receive more invalidations on its other pages.
74+
// Remove tracking from this page only.
75+
UntrackImageHead(image_id);
76+
} else if (image_begin < page_addr) {
77+
// This page access does not modify the image but the page should be untracked.
78+
// We should not mark this image as dirty now. If it really was modified
79+
// it will receive more invalidations on its other pages.
80+
UntrackImageTail(image_id);
81+
} else {
82+
// Image begins and ends on this page so it can not receive any more invalidations.
83+
// We will check it's hash later to see if it really was modified.
84+
if (image.hash == 0) {
85+
// Initialize hash
86+
const u8* addr = std::bit_cast<u8*>(image.info.guest_address);
87+
image.hash = XXH3_64bits(addr, image.info.guest_size_bytes);
6788
}
68-
return;
89+
image.flags |= ImageFlagBits::MaybeCpuDirty;
90+
UntrackImage(image_id);
6991
}
70-
71-
if (addr < image.cpu_addr_end) {
72-
// Ensure image is reuploaded when accessed again.
73-
image.flags |= ImageFlagBits::CpuDirty;
74-
}
75-
// Untrack image, so the range is unprotected and the guest can write freely.
76-
UntrackImage(image_id);
7792
});
7893
}
7994

@@ -443,9 +458,12 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
443458
False(image.flags & ImageFlagBits::CpuDirty)) {
444459
// The image size should be less than page size to be considered MaybeCpuDirty
445460
// So this calculation should be very uncommon and reasonably fast
446-
ASSERT(image.info.guest_size_bytes <= 4_KB);
447-
const u8* addr = std::bit_cast<u8*>(image.info.guest_address);
448-
const u64 hash = XXH3_64bits(addr, image.info.guest_size_bytes);
461+
// For now we'll just check up to 64 first pixels
462+
const auto addr = std::bit_cast<u8*>(image.info.guest_address);
463+
const auto w = std::min(image.info.size.width, u32(8));
464+
const auto h = std::min(image.info.size.height, u32(8));
465+
const auto size = w * h * image.info.num_bits / 8;
466+
const u64 hash = XXH3_64bits(addr, size);
449467
if (image.hash == hash) {
450468
image.flags &= ~ImageFlagBits::MaybeCpuDirty;
451469
return;
@@ -539,7 +557,7 @@ void TextureCache::RegisterImage(ImageId image_id) {
539557
ASSERT_MSG(False(image.flags & ImageFlagBits::Registered),
540558
"Trying to register an already registered image");
541559
image.flags |= ImageFlagBits::Registered;
542-
ForEachPage(image.cpu_addr, image.info.guest_size_bytes,
560+
ForEachPage(image.info.guest_address, image.info.guest_size_bytes,
543561
[this, image_id](u64 page) { page_table[page].push_back(image_id); });
544562
}
545563

@@ -548,7 +566,7 @@ void TextureCache::UnregisterImage(ImageId image_id) {
548566
ASSERT_MSG(True(image.flags & ImageFlagBits::Registered),
549567
"Trying to unregister an already unregistered image");
550568
image.flags &= ~ImageFlagBits::Registered;
551-
ForEachPage(image.cpu_addr, image.info.guest_size_bytes, [this, image_id](u64 page) {
569+
ForEachPage(image.info.guest_address, image.info.guest_size_bytes, [this, image_id](u64 page) {
552570
const auto page_it = page_table.find(page);
553571
if (page_it == nullptr) {
554572
UNREACHABLE_MSG("Unregistering unregistered page=0x{:x}", page << PageShift);
@@ -566,62 +584,106 @@ void TextureCache::UnregisterImage(ImageId image_id) {
566584

567585
void TextureCache::TrackImage(ImageId image_id) {
568586
auto& image = slot_images[image_id];
569-
if (True(image.flags & ImageFlagBits::Tracked)) {
587+
const auto image_begin = image.info.guest_address;
588+
const auto image_end = image.info.guest_address + image.info.guest_size_bytes;
589+
if (image_begin == image.track_addr && image_end == image.track_addr_end) {
570590
return;
571591
}
572-
if (True(image.flags & ImageFlagBits::TailTracked)) {
573-
// Re-track only image head
574-
TrackImageHead(image_id);
575-
} else {
592+
593+
if (!image.IsTracked()) {
576594
// Re-track the whole image
577-
image.flags |= ImageFlagBits::Tracked;
578-
tracker.UpdatePagesCachedCount(image.cpu_addr, image.info.guest_size_bytes, 1);
595+
image.track_addr = image_begin;
596+
image.track_addr_end = image_end;
597+
tracker.UpdatePagesCachedCount(image_begin, image.info.guest_size_bytes, 1);
598+
} else {
599+
if (image_begin < image.track_addr) {
600+
TrackImageHead(image_id);
601+
}
602+
if (image.track_addr_end < image_end) {
603+
TrackImageTail(image_id);
604+
}
579605
}
580606
}
581607

582608
void TextureCache::TrackImageHead(ImageId image_id) {
583609
auto& image = slot_images[image_id];
584-
if (True(image.flags & ImageFlagBits::Tracked)) {
610+
const auto image_begin = image.info.guest_address;
611+
if (image_begin == image.track_addr) {
585612
return;
586613
}
587-
ASSERT(True(image.flags & ImageFlagBits::TailTracked));
588-
image.flags |= ImageFlagBits::Tracked;
589-
image.flags &= ~ImageFlagBits::TailTracked;
590-
const auto size = tracker.GetNextPageAddr(image.cpu_addr) - image.cpu_addr;
591-
tracker.UpdatePagesCachedCount(image.cpu_addr, size, 1);
614+
ASSERT(image.track_addr != 0 && image_begin < image.track_addr);
615+
const auto size = image.track_addr - image_begin;
616+
image.track_addr = image_begin;
617+
tracker.UpdatePagesCachedCount(image_begin, size, 1);
618+
}
619+
620+
void TextureCache::TrackImageTail(ImageId image_id) {
621+
auto& image = slot_images[image_id];
622+
const auto image_end = image.info.guest_address + image.info.guest_size_bytes;
623+
if (image_end == image.track_addr_end) {
624+
return;
625+
}
626+
ASSERT(image.track_addr_end != 0 && image.track_addr_end < image_end);
627+
const auto addr = image.track_addr_end;
628+
const auto size = image_end - image.track_addr_end;
629+
image.track_addr_end = image_end;
630+
tracker.UpdatePagesCachedCount(addr, size, 1);
592631
}
593632

594633
void TextureCache::UntrackImage(ImageId image_id) {
595634
auto& image = slot_images[image_id];
596-
ASSERT(!True(image.flags & ImageFlagBits::Tracked) ||
597-
!True(image.flags & ImageFlagBits::TailTracked));
598-
if (True(image.flags & ImageFlagBits::Tracked)) {
599-
image.flags &= ~ImageFlagBits::Tracked;
600-
tracker.UpdatePagesCachedCount(image.cpu_addr, image.info.guest_size_bytes, -1);
601-
}
602-
if (True(image.flags & ImageFlagBits::TailTracked)) {
603-
image.flags &= ~ImageFlagBits::TailTracked;
604-
const auto addr = tracker.GetNextPageAddr(image.cpu_addr);
605-
const auto size = image.info.guest_size_bytes - (addr - image.cpu_addr);
635+
if (!image.IsTracked()) {
636+
return;
637+
}
638+
const auto addr = image.track_addr;
639+
const auto size = image.track_addr_end - image.track_addr;
640+
image.track_addr = 0;
641+
image.track_addr_end = 0;
642+
if (size != 0) {
606643
tracker.UpdatePagesCachedCount(addr, size, -1);
607644
}
608645
}
609646

610647
void TextureCache::UntrackImageHead(ImageId image_id) {
611648
auto& image = slot_images[image_id];
612-
if (False(image.flags & ImageFlagBits::Tracked)) {
649+
const auto image_begin = image.info.guest_address;
650+
if (!image.IsTracked() || image_begin < image.track_addr) {
651+
return;
652+
}
653+
const auto addr = tracker.GetNextPageAddr(image_begin);
654+
const auto size = addr - image_begin;
655+
image.track_addr = addr;
656+
if (image.track_addr == image.track_addr_end) {
657+
// This image spans only 2 pages and both are modified,
658+
// but the image itself was not directly affected.
659+
// Cehck its hash later.
660+
MarkAsMaybeDirty(image_id, image);
661+
}
662+
tracker.UpdatePagesCachedCount(image_begin, size, -1);
663+
}
664+
665+
void TextureCache::UntrackImageTail(ImageId image_id) {
666+
auto& image = slot_images[image_id];
667+
const auto image_end = image.info.guest_address + image.info.guest_size_bytes;
668+
if (!image.IsTracked() || image.track_addr_end < image_end) {
613669
return;
614670
}
615-
image.flags |= ImageFlagBits::TailTracked;
616-
image.flags &= ~ImageFlagBits::Tracked;
617-
const auto size = tracker.GetNextPageAddr(image.cpu_addr) - image.cpu_addr;
618-
tracker.UpdatePagesCachedCount(image.cpu_addr, size, -1);
671+
ASSERT(image.track_addr_end != 0);
672+
const auto addr = tracker.GetPageAddr(image_end);
673+
const auto size = image_end - addr;
674+
image.track_addr_end = addr;
675+
if (image.track_addr == image.track_addr_end) {
676+
// This image spans only 2 pages and both are modified,
677+
// but the image itself was not directly affected.
678+
// Cehck its hash later.
679+
MarkAsMaybeDirty(image_id, image);
680+
}
681+
tracker.UpdatePagesCachedCount(addr, size, -1);
619682
}
620683

621684
void TextureCache::DeleteImage(ImageId image_id) {
622685
Image& image = slot_images[image_id];
623-
ASSERT_MSG(False(image.flags & ImageFlagBits::Tracked), "Image was not untracked");
624-
ASSERT_MSG(False(image.flags & ImageFlagBits::TailTracked), "Image was not untracked");
686+
ASSERT_MSG(!image.IsTracked(), "Image was not untracked");
625687
ASSERT_MSG(False(image.flags & ImageFlagBits::Registered), "Image was not unregistered");
626688

627689
// Remove any registered meta areas.

src/video_core/texture_cache/texture_cache.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,15 +242,15 @@ class TextureCache {
242242

243243
/// Track CPU reads and writes for image
244244
void TrackImage(ImageId image_id);
245-
246-
/// Track CPU reads and writes for image
247245
void TrackImageHead(ImageId image_id);
246+
void TrackImageTail(ImageId image_id);
248247

249248
/// Stop tracking CPU reads and writes for image
250249
void UntrackImage(ImageId image_id);
251-
252-
/// Stop tracking CPU reads and writes for the first page of the image
253250
void UntrackImageHead(ImageId image_id);
251+
void UntrackImageTail(ImageId image_id);
252+
253+
void MarkAsMaybeDirty(ImageId image_id, Image& image);
254254

255255
/// Removes the image and any views/surface metas that reference it.
256256
void DeleteImage(ImageId image_id);

0 commit comments

Comments
 (0)