File reads into GPU-tracked memory: one invalidation per chunk instead of a fault per page

The game streams its city blocks with reads of 10-30 MB; copied page by page into GPU-tracked
memory that was one write fault per 4 KB page: João's hitch lines (10-29, PGO build) show
4,000-7,600 write faults and 50-170 ms in each frame that read a block. A read chunk of 64 KB or
more is now marked CPU-written first, as its faults would have done (GuestWriteFault: GPU-written
pages read back, the rest unprotected), then copied without faulting. ISSN_READ_INVALIDATE=0
restores the fault path.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Eij6gW2nnTUK9BowHuBVZZ
This commit is contained in:
Claude committed 2026-10-29 23:43:05 -03:00
1 parent 83821a8b6d
commit 1ff2d72fe3
1 file changed
+21 -3
+21 -3
View File
@@ -712,7 +712,25 @@ extern "C" int issngpu_text_input_poll(char* out, uint64_t size) {
return state;
}
// issn: ISSN_WRITE_MERGE was the old core's; the new one has no merge path (writes fault normally).
extern "C" int issngpu_cpu_write(void*, const void*, int, uint64_t) {
return 0;
// issn 0.3.6: a file read copied into GPU-tracked memory (src/runtime_file.c bounce_read). The
// game streams its city blocks this way, 10-30 MB at a time; page by page that was one write
// fault per 4 KB page (João's hitch lines 10-29: 4,000-7,600 faults and 50-170 ms in the frames
// that read a block). The whole chunk is now marked CPU-written first, exactly as its faults
// would have done (GuestWriteFault: GPU-written pages are read back, the rest unprotected), then
// copied without faulting. Small reads keep the fault path. ISSN_READ_INVALIDATE=0: off.
extern "C" int issngpu_cpu_write(void* dst, const void* src, int, uint64_t size) {
static const bool enabled = [] {
const char* v = std::getenv("ISSN_READ_INVALIDATE");
return !(v && v[0] == '0');
}();
if (!enabled || size < (64u << 10)) {
return 0;
}
auto* rasterizer = Core::Memory::Instance()->GetRasterizer();
if (!rasterizer) {
return 0;
}
rasterizer->InvalidateMemory(reinterpret_cast<VAddr>(dst), size, VideoCore::InvalidateOrigin::GuestWriteFault);
std::memcpy(dst, src, size);
return 1;
}