mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Hand an overwritten render target's image on after 8 presents while the card is past its pressure share, and free the ones no texture took after 32.
At 3840x2160 the targets moved in 16 presents hold 3.1 GiB, which a 16 GiB card does not have beside the 10 GiB of a town. A mark reaches its entry within three frames of the draw (four read-back copies, one every four submissions), so eight presents without a stamp are enough there. The early drop waits four times that: at ten presents it took the images the reuse was about to hand on (7,301 dropped, 7,672 made, 5,226 reused in one run); at 32 the same run made 3,338 and reused 8,004. The walk from the bug capture at 3840x2160 with the budget taken as 13.2 GiB, a 16 GiB card's: 10.9 to 11.4 GiB in use, at most 1.6 GiB of released targets, no image that could not be made and none in system memory. A player's log from such a card at that size had 12.2 GiB of released targets and 22.2 GiB in use at 2 frames a second. Without the budget, at 3416x1440: 10.0 to 10.7 GiB, as before this change. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
## Fixed
|
||||
|
||||
- **Video memory no longer fills up while the camera moves** (by epicmeme546). The game lays its render targets out
|
||||
anew in every frame, one behind the other in one block of memory. One of them, a shadow map, changes its size with
|
||||
the view (1141x1141 to 1917x1917 in Kokiri Forest, a texel or two a frame), and every target behind it then lies at
|
||||
a new address in each frame. A moved target should take over the image of the one it replaces, but that image
|
||||
counted as in use for as long as the game had not recycled the old target's texture object, so every frame got about
|
||||
a dozen new images and each old one stayed for 120 frames or more: 6.7 GiB of them at 3416x1440 and 12.2 GiB at
|
||||
3840x2160, on top of the 10 GiB the area needs. A 20 GiB card ran full twice in five minutes of Kokiri Forest and a
|
||||
16 GiB card in Castle Town (images that could not be made or went to system memory, 2 to 4 frames a second, then
|
||||
the game ended). An image that another target was drawn over now goes to the next target of its size once nothing
|
||||
has drawn with it or sampled it for 16 frames, and past 80 % of the card's memory such images are freed at once
|
||||
instead of ten seconds later. Walking 28 metres from a save in Kokiri Forest and then around it at 3416x1440: 15.9 GiB
|
||||
of video memory in use before, 14 GiB again on each lap; 9.7 to 10.6 GiB now, with at most 2.2 GiB of released
|
||||
targets where there were 6.9 GiB, and 3,609 images made in the run where there were 6,970.
|
||||
- **Video memory no longer fills up while the camera moves** (by epicmeme546). The game lays its render targets out anew
|
||||
in every frame, one behind the other in one block of memory. One of them, a shadow map, changes its size with the view
|
||||
(1141x1141 to 1917x1917 in Kokiri Forest, a texel or two a frame), and every target behind it then lies at a new
|
||||
address in each frame. A moved target should take over the image of the one it replaces, but that image counted as in
|
||||
use for as long as the game had not recycled the old target's texture object, so every frame got about a dozen new
|
||||
images and each old one stayed for 120 frames or more: 6.7 GiB of them at 3416x1440 and 12.2 GiB at 3840x2160, on top
|
||||
of the 10 GiB the area needs. A 20 GiB card ran full twice in five minutes of Kokiri Forest (images that could not be
|
||||
made, 4 frames a second, then the game ended) and a 16 GiB card in Castle Town (images in system memory, 2 frames a
|
||||
second). An image that another target was drawn over now goes to the next target of its size once nothing has drawn
|
||||
with it or sampled it for 16 frames, or for 8 once the card is past 80 % of its memory, where such images are also
|
||||
freed after 32 frames instead of ten seconds. Walking 28 metres from a save in Kokiri Forest and then around it at
|
||||
3416x1440: 15.9 GiB of video memory in use before and 14 GiB again on each lap; 9.7 to 10.7 GiB now, with at most 2.2
|
||||
GiB of released targets where there were 6.9 GiB, and 3,609 images made in the run where there were 6,970. The same
|
||||
walk at 3840x2160 with the memory budget of a 16 GiB card: 10.9 to 11.4 GiB, at most 1.6 GiB of them released.
|
||||
|
||||
@@ -718,6 +718,13 @@ static int marks_tell(void);
|
||||
// The presents a released entry must have gone unused before its image may go to another texture (create_tex): the
|
||||
// pool's marks reach an entry a few presents after the draw that sampled it.
|
||||
#define REUSE_UNUSED 16
|
||||
// The same for an overwritten entry while the card is past the VRAM pressure's share of its budget (over_share): what
|
||||
// the marks need and no more. A mark is read at most MARKS_RB copies of MARKS_EVERY submissions after its draw
|
||||
// (vk_exec_draw.c vk_exec_pool_marks), three frames of six submissions, so after eight presents without a stamp none
|
||||
// is on its way. At 3840x2160 the targets moved in 16 presents hold 3.1 GiB, which a 16 GiB card does not have beside
|
||||
// the 10 GiB of a town.
|
||||
#define REUSE_UNUSED_FULL 8
|
||||
static int over_share; // sweep_pressure: the driver's figure of the memory in use is past that share
|
||||
// The released entries of one parameter set create_tex looks at, newest release first. While the game's layout moves
|
||||
// in every frame, each frame releases every target of a set and none of them is unused yet for REUSE_UNUSED presents:
|
||||
// with 128 looked at, eight targets of one set a frame hid every older entry behind the young ones and each texture
|
||||
@@ -1512,7 +1519,8 @@ static Tex *create_tex(const tex_t *t, const TexKey *k, int defer_init) {
|
||||
if (q->rel_epoch == submit_epoch || now - q->rel_frame < 2) { n_reuse_young++; continue; }
|
||||
int over = q->overwritten && marks;
|
||||
// still drawn with or sampled: its content is asked for
|
||||
if (over ? sampled_lately(q, now, REUSE_UNUSED) : used_lately(q, now, REUSE_UNUSED)) {
|
||||
if (over ? sampled_lately(q, now, over_share ? REUSE_UNUSED_FULL : REUSE_UNUSED)
|
||||
: used_lately(q, now, REUSE_UNUSED)) {
|
||||
n_reuse_used++;
|
||||
continue;
|
||||
}
|
||||
@@ -2705,10 +2713,11 @@ static int sampled_lately(const Tex *e, uint64_t now, uint64_t within) { return
|
||||
// drop makes it again that way, so an entry something still uses stays; so does one the image reuse would take
|
||||
// (create_tex, REUSE_UNUSED).
|
||||
// full: the card is past the VRAM pressure's share of its budget by the driver's own figure (sweep_pressure). The
|
||||
// wait is then OVERWRITTEN_FULL presents, the time the image reuse leaves an entry alone: an image no texture took in
|
||||
// that time holds nothing the game can ask for, and the memory it keeps for ten seconds more is what the next image
|
||||
// fails for.
|
||||
#define OVERWRITTEN_FULL (REUSE_UNUSED + 2)
|
||||
// wait is then OVERWRITTEN_FULL presents, four times what the image reuse leaves an entry alone for there: an image no
|
||||
// texture took in that time holds nothing the game can ask for, and the memory it keeps for ten seconds more is what
|
||||
// the next image fails for. Not sooner: at ten presents this took the images the reuse was about to hand on, 7,301 in
|
||||
// a run at 3840x2160 that then made 7,672 images and reused 5,226.
|
||||
#define OVERWRITTEN_FULL (REUSE_UNUSED_FULL * 4)
|
||||
static uint64_t n_over_full; // since the last perf line: of n_over_drops, dropped with the card that full
|
||||
static void drop_overwritten(int full) {
|
||||
static int used_too = -1;
|
||||
@@ -3365,7 +3374,8 @@ static void sweep_pressure(void) { // tex_lock held
|
||||
// at 100 % of its budget by this figure was at 81 % by the other, 3.1 GiB of it holes, and nothing gave way.
|
||||
uint64_t cap = released_cap_bytes(), keep = cap, vused = 0, vbudget = 0;
|
||||
int vexact, vknown = vk_mem_vram(&vused, &vbudget, &vexact);
|
||||
drop_overwritten(vknown && vram_pressure && vused > vbudget / 100 * (uint64_t)vram_pressure);
|
||||
over_share = vknown && vram_pressure && vused > vbudget / 100 * (uint64_t)vram_pressure;
|
||||
drop_overwritten(over_share);
|
||||
drop_aged();
|
||||
// the bound, or more of it while the hold empties the released entries within minutes and the card and the
|
||||
// system have room (vk_tex_release.h trl_keep): a young entry dropped there is one the game may still take back
|
||||
|
||||
Reference in New Issue
Block a user