Repository navigation
vk: render target images reused from a pool, not made and destroyed for each of OoT's shifting transient targets - #1416
Merged
Conversation
…or each of OoT's shifting transient targets OoT makes a frame's transient targets in a scratch heap whose offsets shift with what came before them in the frame, so each shifted one is a texture with a new image, and every 60 presents the dead-target sweep (NotRexed#899) let go of 300-700 of them at once, destroyed in the next present: 20-65 ms on the replaying thread, about once a second while the camera moves (RTX 5070, Kokiri Forest: 10,500 images made and destroyed in 4.5 minutes, 17 GB). A render target's image whose texture is gone now waits in a pool by its create info, with its views, and a new texture of that create info takes it. It is still put into GENERAL from UNDEFINED and cleared as a new image is, so nothing it held shows. Uncompressed colour and depth targets only; bounded by RX_VK_TARGET_POOL_MB (default 1024, 0: off, as before), given back while VRAM is near what the driver allows, and an image unused in it for 120 presents is destroyed, at most 16 a present. tests/test_target_image_pool.py keeps the rules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
|
This landed in the v2.0.12 branch (merged there for testing; it reaches |
27thLiz
pushed a commit
to 27thLiz/Hookshot
that referenced
this pull request
Nov 10, 2026
…wept every 10 presents; the target pool bound 256 MB Follow-up to NotRexed#1416. OoT's transient targets, made and let go all the time, shared the image pool's 128 MB blocks with the textures that stay: each one gone left a hole beside a texture that kept its block. In Kokiri Forest the pool's 47-54 blocks (6-6.9 GB) held 1.9-3.6 GB of images, VRAM sat at 93-98% of what the driver allows, and an image made then took 30-70 ms (RTX 5070). - Images texture_get makes for a target (not for sampling) come from blocks of their own (RX_VK_TARGET_BLOCKS=0: as before), and only those go to the target pool. - The dead targets are swept every 10 presents (RX_VK_DEAD_EVERY, 60 before): the pool got 300-700 at once and the new targets of the next second missed most of them. The choice is cheap (1930 textures ordered in 0.3 ms). - The target pool's bound comes down to 256 MB. - Every 600 presents the log says what the image blocks hold (vma_log_image_blocks). tests/test_target_image_pool.py checks the new rules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
|
Reopened: closing this was a mistake on my side. It was tested in the v2.0.12 branch, and it will be merged into main here, so it shows as merged. Sorry for the noise. |
… main's retries for a refused compressed image)
NotRexed
added a commit
to DUDUYG/Hookshot
that referenced
this pull request
Nov 10, 2026
…l size, target-only key and own blocks kept, with main's retries for a refused compressed image)
NotRexed
added a commit
that referenced
this pull request
Nov 10, 2026
…wept every 10 presents (follow-up to #1416) (#1436) * vk: render target images reused from a pool, not made and destroyed for each of OoT's shifting transient targets OoT makes a frame's transient targets in a scratch heap whose offsets shift with what came before them in the frame, so each shifted one is a texture with a new image, and every 60 presents the dead-target sweep (#899) let go of 300-700 of them at once, destroyed in the next present: 20-65 ms on the replaying thread, about once a second while the camera moves (RTX 5070, Kokiri Forest: 10,500 images made and destroyed in 4.5 minutes, 17 GB). A render target's image whose texture is gone now waits in a pool by its create info, with its views, and a new texture of that create info takes it. It is still put into GENERAL from UNDEFINED and cleared as a new image is, so nothing it held shows. Uncompressed colour and depth targets only; bounded by RX_VK_TARGET_POOL_MB (default 1024, 0: off, as before), given back while VRAM is near what the driver allows, and an image unused in it for 120 presents is destroyed, at most 16 a present. tests/test_target_image_pool.py keeps the rules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * vk: render targets' images in VMA blocks of their own; dead targets swept every 10 presents; the target pool bound 256 MB Follow-up to #1416. OoT's transient targets, made and let go all the time, shared the image pool's 128 MB blocks with the textures that stay: each one gone left a hole beside a texture that kept its block. In Kokiri Forest the pool's 47-54 blocks (6-6.9 GB) held 1.9-3.6 GB of images, VRAM sat at 93-98% of what the driver allows, and an image made then took 30-70 ms (RTX 5070). - Images texture_get makes for a target (not for sampling) come from blocks of their own (RX_VK_TARGET_BLOCKS=0: as before), and only those go to the target pool. - The dead targets are swept every 10 presents (RX_VK_DEAD_EVERY, 60 before): the pool got 300-700 at once and the new targets of the next second missed most of them. The choice is cheap (1930 textures ordered in 0.3 ms). - The target pool's bound comes down to 256 MB. - Every 600 presents the log says what the image blocks hold (vma_log_image_blocks). tests/test_target_image_pool.py checks the new rules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: NotRexed <therealnothingfn@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Render target images are reused from a pool instead of being made and destroyed for each of OoT's shifting transient targets.
OoT makes a frame's transient targets in a scratch heap, and their offsets shift with what came before them in the frame. So each shifted target is a texture with a new image. Every 60 presents, the dead-target sweep (#899) lets go of the dead ones, and the next present destroys them all at once. In Kokiri Forest that is 300-700 images per sweep, at about 0.07 ms each: a 20-65 ms stall on the replaying thread, about once a second while the camera moves.
In one 4.5-minute run, 10,500 images (17 GB) were made and destroyed this way. The sweep's choice is cheap (under 1 ms). All of the stall is the destruction.
Change (
gpu/vk/vk_texture.cpp,vk_texture.h)VkImageCreateInfo(pool_key_of). The dead list puts them there once the GPU is done with them, instead of destroying them.create_imageis asked. It is still put intoGENERALfromUNDEFINEDand cleared exactly as a new image is, so nothing it held shows.RX_VK_TARGET_POOL_MB(default 1024;0turns the pool off and every image is destroyed as before).pool_trimdestroys at most 16 images a present (64 while VRAM is short), so there is never a burst.vk: render target images: N reused from the pool, M made new, K destroyed from it; it holds X (Y MB).Measured
HOS_HEADLESS,HOS_AUDIO=0), a Kokiri Forest save, the same scripted 36 s walk with camera turns each run. The numbers are the in-play part only (presents 3300 and on, after the save's load).RX_VK_TARGET_POOL_MB=0, alternated.Not covered
pressure > allowed / 10 * 9) to be given back. I could not test that on a small card.Tests
tests/test_target_image_pool.py(source checks, 7 cases):0turns the pool off;create_imageand still goesUNDEFINED→GENERALand is cleared;tests/run_all.pyon every test that readsvk_texture.cpp, plustest_vulkan_clear_mip.pyandtest_parallel_init_order.pywith the Vulkan headers.RX_VK_ONLY=1 nx2/build.py --standalone).🤖 Generated with Claude Code