Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render Targets leak memory #5744

Closed
WardenPotato opened this issue Feb 20, 2024 · 2 comments
Closed

Render Targets leak memory #5744

WardenPotato opened this issue Feb 20, 2024 · 2 comments

Comments

@WardenPotato
Copy link

Details

When a Render Target is created its memory will never be cleared even if its no longer used, neither do map reloads or joining other servers clear them from memory, they can really accumulate over time or if you use them for more dynamic purposes.

Branches/platforms affected: All

The issue can simply be reproduced by making a Render Target, no matter what you do it will never get removed.
Heres a script to create a render target with something on it and then later observe the result, the commented out portion of code should be uncommented for the first run to get something rendered on the RT, then you can reload the map or otherwise and run it again with the portion commented out to see that the contents still exist.

local testRenderTarget = GetRenderTarget( "rt_testing_target", 512, 512 )

local testRenderTargetMaterial = CreateMaterial("rt_testing_material", "UnlitGeneric", {
    ["$basetexture"] = testRenderTarget:GetName(),
})

-- Only on first run!!
-- surface.CreateFont( "TestingRenderTargets", {
--     font = "Roboto-Bold",
--     size = 60
-- } )

-- render.PushRenderTarget( testRenderTarget )
--     render.Clear( 255, 0, 0, 255, true, true )
--     cam.Start2D()
--         draw.SimpleText( "Hello there!", "TestingRenderTargets", 256, 256, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
--     cam.End2D()
-- render.PopRenderTarget()
-- End of only on first run!

hook.Add( "HUDPaint", "tr_testing_DrawOverlay", function()
    surface.SetDrawColor( color_white )
    surface.SetMaterial( testRenderTargetMaterial )
    surface.DrawTexturedRect( 25, 25, 512, 512 )
end )

After observing mat_dumptextures the Refcount is still at 1 for some reason, i assume these are dangling references from somewhere in the engine or lua.
Texture: 'rt_testing_target' RefCount: 1
The behaviour seems to be quite consistent:

Load map
Run script
Refcount 2

changelevel another map
Refcount 1
Run script
Refcount 2

changelevel another map
Refcount 1
Run script
Refcount 2

disconnect and load another map
Refcount 1
Run script
Refcount 2

disconnect and join a server
Refcount 1
Run script
Refcount 2

changelevel on server
Refcount 1
Run script
Refcount 2

disconnect and load a singleplayer map again
Refcount 1
Run script
Refcount 2

The engine should clean up any material/texture without references upon a map load through bool CQueuedLoader::BeginMapLoading( const char *pMapName, bool bLoadForHDR, bool bOptimizeMapReload )(and other paths) but because of the dangling reference its not cleaned up.

A handy addition aswell would be API bindings for ITexture and IMaterial its DeleteIfUnreferenced() and GetReferenceCount() to allow for manual collection when using render targets in a more temporary and dynamic fashion.

If fixed/added this can close:
Facepunch/garrysmod-requests#435
#5011

Thanks also goes out to @A1steaksa

@robotboy655
Copy link
Contributor

I have made some changes to address this on dev. Should get cleaned up on disconnect. (As well as map load if they are referenced from a material)

@WardenPotato
Copy link
Author

Can confirm it works as expected now on the dev branch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants