Object Lags on First Instantiation... But Not Because of Shaders...?

Godot Version

v4.6.1.stable.steam [14d19694e]

Question

So I’d like to ask for some advice on how to handle a weird situation I’ve run into. One of the objects in my game, a somewhat complicated one, despite being preloaded (or loaded), causes a lag spike the very first time I call instantiate() on it after executing the game, then never again, but what’s pertinent about this is that… it seems to NOT be shader related! If I make the root of the object invisible so that it doesn’t render at all, the lag STILL happens the first time it’s instantiated following execution and then never again!

The advice I’m asking for is simply what steps I should take to figure out what’s causing the initial lag or towards eliminating said lag. I mean, since it’s the instantiate() call itself that actually causes the lag I could just call it during the game’s initial boot sequence and immediately remove it from existence without even adding it to the scenetree, but the more I can learn about what might cause lag spikes outside of shader compilation, the better equipped I will be to deal with any similar issues in the future! :B

Well firstly, this isn’t enough information here to do much, show the node tree of your object, how everything looks in there, maybe the code used to load/instantiate etc.
Secondly, making a node invisible does not remove it from memory nor does it stop it from processing, so anything it is using (i.e. textures, meshes, shaders etc.) will still be present in memory, and processed, so I don’t believe this is an adequate way to check if the lag is caused by shader processing.
Third, I would try using the built in profilers to try and figure where exactly the issue is, enable both the regular and visual profiler, and see in the monitors if you see any spikes in the graphs when the instantiation process happens, they can tell you a lot, i.e. if it’s related to something CPU or GPU bound.

1 Like

Again, just asking for general advice on how to deal with initial lag spikes not caused by shader compilation, since I know shader compilation is a BIG reason for most lag spikes, but I already understand how to deal with those.

Making the node invisible was my way to check if shader compilation was the culprit or not, since I know from past experience that shaders generally don’t compile until the first attempt to render one. Since I am preloading (or loading, happens either way) the packed scene into memory, I was under the assumption that would put all the required content into memory ahead of time but apparently that’s not precisely it?

Using the profiler I find that when the lag occurs there’s no GPU spike, but a CPU spike, and curiously it’s being profiled as “Render CanvasItems”…??? For a 3D scene…??? What…??? o_O

How did you determine that?

By literally commenting out everything to do with when the instantiation normally occurs, testing, seeing no lag spike, then ONLY uncommenting the instantiate() call and nothing else, testing, and seeing the lag spike. I don’t even have to add it to the scenetree or anything, the first call to instantiate() causes the lag spike on this particular packed scene. Additional calls do not cause the lag spike. It also happens regardless of if the packed scene is put into memory through preload() or load().

Well, my general advice is “use profiler”, if you need any more in-depth help you’ll need to provide more information.

2 Likes

Print a timestamp right before and right after instantiate() call. How much time does it take?

Also, post the scene structure.

1 Like

The profiler shows a CPU spike in “Render CanvasItems” of about 5 ms, which really has me clueless because even though we’re talking a very complex scene object, it ONLY consists of Node3D-based nodes, nothing which does CanvasItem rendering…? Unless Label3Ds are involved with that, but then that still makes me wonder why it only happens the first time it’s instantiated and not additional times. Also, the scene structure is 294 nodes large, including the nodes from all child scenes… I don’t think you want me to post the entire thing. What I can say is that the kinds of nodes in play are Node3D, MeshInstance3D, Area3D, CollisionShape3D, Sprite3D, Label3D, and a few AnimationPlayers which each don’t do anything more than flash or fade the child scenes they are a part of.

…though thinking about it now… maybe just the sheer complexity of the scene is what’s causing the initial lag spike on the first instantiation? I did do some testing by having the game’s boot process instantiate the scene and immediately queue_free() that instance and that prevents the first actual appearance of the object from causing a lag spike, but again, if there’s other things to check or keep in mind I want to know those tricks! :B

Instantiation is not the same as appearance. Does the instantiation take tame or the addition to the tree? As I said, put timestamps around instantiate() to see exactly how much time it takes and if it is indeed it that causes the spike.

It’s the instantiation. The lag spike happens on the first instantiate() only, regardless of if I add it to the scenetree or not. If NOTHING else is called other than instantiate(), the lag spike still happens, and if I comment out the instantiate() too the lag spike disappears. I’m avoiding printing timestamps because I’ve never actually done that and would have to look up how to do it, plus I’m not sure what that would help with given that I have already pinned it down to the actual instantiate() command.

It will give you the precise time measurement of how long it takes to execute something. This is generally useful to know. The time is in microseconds.

var t = Time.get_ticks_usec()
# put stuff to measure here
print("Time elapsed: ", Time.get_ticks_usec() - t )

…reports as around 5,000 microseconds… so 5 ms, just like the profiler was indicating, as the time difference between placing a print() right before instantiate() and right after.

…HOWEVER, I noticed that even though the lag spike only happens once, it STILL takes 5 ms to instantiate the scene every time…??? Nothing is reported on the GPU side of things and, realistically, 5 ms shouldn’t be causing a lag spike at a locked 60 FPS… this is getting weird…

5 ms is definitely not a spike at 60 fps.

It’s likely gpu related. Hard to tell specifically without seeing what exactly have you crammed inside that scene.

OK, so that leads me back around to my original desire for advice: What can I do to stop lag spikes when shader compilation is not the cause? Again, NOTHING is showing up GPU-wise on the profiler when the lag spike happens, plus despite the complexity of the packed scene there’s only four shader programs in play inside and my shader pre-compiler object I place in the scene in front of the camera at boot has all four of them accounted for, including the textures they use.

Nothing until you know the cause. In general, you should strive to keep the geometry and textures in your scenes as economical as possible. It’s not uncommon that people just mindlessly pile stuff into scenes, not knowing/caring at all about polygon counts or texture resolutions.

If the scene is very large, consider breaking it into multiple smaller scenes and loading/instantiating bit by bit or streaming.

Already on top of that; This isn’t my first gamedev rodeo, not by a long shot, just my first major project using Godot Engine so I’m still learning all the quirks and nuances and sometimes I run into trouble finding answers on my own accord.

The packed scene in question is the most complicated in the game by far because it’s effectively a universal editing box. When the player is editing a world in the game, they use a special tool which allows them to click on an element in the world and it pulls up this editing box with controls for moving the object in the world around, rotating, scaling, bring up properties, editing materials, and connecting logic links. It doesn’t show ALL of these things at once, but is prepped and ready for each possibility.

What happens with video ram when the scene is instantiated? Enable the chart in debugger/monitors.

Just checked; Absolutely nothing. That’s what I would expect too as all of the necessary textures and shaders should already be loaded by the time the packed scene is instantiated.

I see a lot of sprites here, you mentioned the spike being on the Render CanvasItems pass, and it being a CPU spike, are the textures for the sprites compressed in any way? It seems like a case where they should be VRAM compressed. (It could also simply be due to a big amount of control nodes being rendered/instantiated at once)

Well then, time to eliminate piece by piece from the scene until the spike disappears. The last thing you removed is the likely culprit :smile:

1 Like