diff --git a/src/graphics/host_gpu/renderer/cache/multiLevelPageTable.h b/src/graphics/host_gpu/renderer/cache/multiLevelPageTable.h index 41fe8d1a9..fa5bce0eb 100644 --- a/src/graphics/host_gpu/renderer/cache/multiLevelPageTable.h +++ b/src/graphics/host_gpu/renderer/cache/multiLevelPageTable.h @@ -219,7 +219,7 @@ private: typename CoarseTable::PageRange coarse_range {}; typename TrackingTable::PageRange tracking_range {}; if (!CoarseTable::TryGetPageRange(address, size, coarse_range) || - !TrackingTable::TryGetPageRange(address, size, tracking_range)) { + (!strict_bytes && !TrackingTable::TryGetPageRange(address, size, tracking_range))) { return {}; } MembershipList candidates; @@ -230,8 +230,8 @@ private: } std::vector result; for (const Registration* registration: candidates) { - if ((!strict_bytes || Overlaps(registration->ranges, address, size)) && - HasTrackingMembership(registration, tracking_range) && + if ((strict_bytes ? Overlaps(registration->ranges, address, size) + : HasTrackingMembership(registration, tracking_range)) && predicate(registration->owner)) { result.push_back(registration->owner); } diff --git a/src/graphics/host_gpu/renderer/cache/textureCache.cpp b/src/graphics/host_gpu/renderer/cache/textureCache.cpp index b3a8ed1f4..9414b3825 100644 --- a/src/graphics/host_gpu/renderer/cache/textureCache.cpp +++ b/src/graphics/host_gpu/renderer/cache/textureCache.cpp @@ -1159,8 +1159,8 @@ ImageId TextureCache::FindImage(ImageDesc& desc, bool exact_format) { if (owner == nullptr) { continue; } - const auto merged_info = result ? ResolveImage(result).info : desc.info; - const auto overlap = ResolveOverlap(merged_info, desc.type, candidate, result); + const auto& merged_info = result ? ResolveImage(result).info : desc.info; + const auto overlap = ResolveOverlap(merged_info, desc.type, candidate, result); if (overlap.image) { result = overlap.image; view_mip = overlap.mip; diff --git a/tests/ImagePageTableTests.cpp b/tests/ImagePageTableTests.cpp index 79958ebf6..6ef71c8c3 100644 --- a/tests/ImagePageTableTests.cpp +++ b/tests/ImagePageTableTests.cpp @@ -117,12 +117,15 @@ void TestStrictByteFilteringAndPredicate() { OwnerIndex index; Check(index.Register(31, {{0x300100, 0x100}}), "first byte-disjoint owner registers"); Check(index.Register(32, {{0x300800, 0x100}}), "second byte-disjoint owner registers"); + Check(index.Register(33, {{0x30f000, 0x100}}), "coarse-only owner registers"); Check(index.TrackingMembershipCount(0x300) == 2, "byte-disjoint owners share one tracking page"); + Check(index.CoarseMembershipCount(3) == 3, + "all owners share one coarse candidate bucket"); Check(index.Query(0x300400, 0x40).empty(), "page hit without byte overlap is filtered out"); const auto page_candidates = index.QueryCandidates(0x300400, 0x40); Check(page_candidates.size() == 2, - "fault candidate query retains byte-disjoint owners on the touched page"); + "fault candidate query retains touched-page owners and rejects coarse-only owners"); const auto first = index.Query(0x300180, 0x10); Check(first.size() == 1 && first.front() == 31, "strict byte overlap selects only the matching owner"); @@ -132,6 +135,20 @@ void TestStrictByteFilteringAndPredicate() { "supplied predicate filters query owners"); } +void TestOwnerIndexAddressSpaceBoundary() { + OwnerIndex index; + constexpr uint64_t last_byte = OwnerIndex::CoarseTable::kAddressSpaceSize - 1; + Check(index.Register(41, {{last_byte, 1}}), "final guest byte registers"); + const auto exact = index.Query(last_byte, 1); + Check(exact.size() == 1 && exact.front() == 41, + "strict query finds an exact overlap at the final guest byte"); + Check(index.Query(last_byte - 1, 1).empty(), + "strict query preserves half-open overlap boundaries"); + const auto page_candidates = index.QueryCandidates(last_byte - 1, 1); + Check(page_candidates.size() == 1 && page_candidates.front() == 41, + "page candidate query retains a byte-disjoint owner on the final tracking page"); +} + } // namespace int main() { @@ -142,6 +159,7 @@ int main() { TestMultiRangeRegistrationDeduplicatesPages(); TestSharedPageUnregisterLifecycle(); TestStrictByteFilteringAndPredicate(); + TestOwnerIndexAddressSpaceBoundary(); std::printf("ImagePageTableTests: all cases passed\n"); return 0; }