psx_residency/host.rs
1//! The edge of the crate: what the engine asks of its host, and what it hands
2//! to the transport.
3
4use crate::key::{Class, ResourceKey};
5use crate::pool::{Handle, PageRun};
6
7/// Where a resource lives on the disc and how much room it needs.
8#[derive(Copy, Clone, Debug, PartialEq, Eq)]
9pub struct Extent {
10 /// First sector of the resource on the disc.
11 pub lba: u32,
12 /// Sectors to read.
13 pub sectors: u32,
14 /// Pages the resource needs in its pool (equal to `sectors` for RAM
15 /// pages, one per slot for texture pages).
16 pub pages: u32,
17 /// Payload length in bytes (at most `pages` pages).
18 pub bytes: u32,
19}
20
21/// Identifies one read request from submission until its outcome is reported.
22#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
23pub struct RequestId(pub u32);
24
25/// One read for the transport to perform: `sectors` sectors from `lba` into
26/// `run` of the pool named by `handle`, sector `n` landing at page
27/// `run.first_page + n`.
28#[derive(Copy, Clone, Debug, PartialEq, Eq)]
29pub struct ReadRequest {
30 /// Identity to report the outcome against.
31 pub id: RequestId,
32 /// The resource being read.
33 pub key: ResourceKey,
34 /// Priority class at submission (see [`Host::promote`]).
35 pub class: Class,
36 /// Allocation the sectors land in.
37 pub handle: Handle,
38 /// The pages of that allocation.
39 pub run: PageRun,
40 /// First sector on the disc.
41 pub lba: u32,
42 /// Sector count.
43 pub sectors: u32,
44 /// Ticks until the data is needed, as the engine's wanted entry said
45 /// (`u32::MAX` when unknown). Earliest deadline first inside a class.
46 pub deadline_ticks: u32,
47 /// An in-flight request that ends exactly at `lba`. A transport can chain
48 /// the two without a seek.
49 pub contiguous_with: Option<RequestId>,
50}
51
52/// A transport's answer to [`Host::submit`].
53#[derive(Copy, Clone, Debug, PartialEq, Eq)]
54pub enum Submit {
55 /// The request is queued.
56 Accepted,
57 /// The queue is full; nothing was queued.
58 Full,
59}
60
61/// How a request ended, reported with [`crate::Residency::complete_read`].
62#[derive(Copy, Clone, Debug, PartialEq, Eq)]
63pub enum ReadOutcome {
64 /// Every sector landed.
65 Done,
66 /// The read failed (drive error, checksum). The resource backs off.
67 Failed,
68 /// The transport stopped the request after [`Host::cancel`]; no sector
69 /// will land in the pages any more.
70 Cancelled,
71}
72
73/// Pages freed by an eviction, reported by [`crate::Residency::step`]. Unlink
74/// the resource (patch the parent, drop cached views) before using resident
75/// data again; the handle is already stale.
76#[derive(Copy, Clone, Debug, PartialEq, Eq)]
77pub struct Eviction {
78 /// The evicted resource.
79 pub key: ResourceKey,
80 /// Its former allocation (stale now).
81 pub handle: Handle,
82 /// The pages it held.
83 pub run: PageRun,
84}
85
86impl Eviction {
87 /// A placeholder for initialising an eviction buffer
88 /// (`[Eviction::NONE; 8]`); [`crate::Residency::step`] overwrites the
89 /// entries it reports.
90 pub const NONE: Eviction = Eviction {
91 key: match ResourceKey::from_u32(0) {
92 Some(key) => key,
93 None => panic!("key 0 is valid"),
94 },
95 handle: Handle::NONE,
96 run: PageRun {
97 first_page: 0,
98 page_count: 0,
99 },
100 };
101}
102
103/// Everything the engine needs from the game, the region graph and the
104/// transport. One value implements it; the engine borrows it for a call.
105pub trait Host {
106 /// Disc position and size of `key`, or `None` when the key is unknown.
107 fn extent(&self, key: ResourceKey) -> Option<Extent>;
108
109 /// Walk distance from the viewer to `key`, in the same units as
110 /// [`crate::Wanted::distance`]. Asked only for resident resources the
111 /// current wanted list did not mention, when eviction needs to rank them.
112 fn walk_distance(&self, key: ResourceKey) -> u32;
113
114 /// Whether the transport can take another request right now.
115 fn can_accept(&self) -> bool {
116 true
117 }
118
119 /// Queue `request`. A [`Submit::Full`] answer rolls the allocation back.
120 fn submit(&mut self, request: &ReadRequest) -> Submit;
121
122 /// Stop `request`. The transport reports [`ReadOutcome::Cancelled`] (or
123 /// [`ReadOutcome::Done`] if the sectors had already landed) through
124 /// [`crate::Residency::complete_read`]; the pages stay reserved until then.
125 fn cancel(&mut self, request: RequestId);
126
127 /// A request already in flight is now wanted at a more urgent class.
128 fn promote(&mut self, _request: RequestId, _class: Class) {}
129
130 /// Move `page_count` pages of `pool` from `from_page` to `to_page` (a
131 /// `memmove`). Called only for categories configured as movable.
132 fn move_pages(&mut self, _pool: u8, _from_page: u32, _to_page: u32, _page_count: u32) {}
133}