If your game does not run smoothly you must first determine where the problem lies. Is it the code from Update function? Or is it rendering?
It’s often difficult to determine the location of the bottleneck intuitively. It’s also very easy to make mistake and lose many hours by optimizing the code that did not require it. Fortunately, FrameProfiler can help you in that process.
How does it work?
FrameProfiler saves the measured values in the log for each frame, e.g .:
-------------------- FrameProfiler begin Frame time: 0.02 secs (we should have 64.29 FPS based on this): - BeforeRender: 0% - Render: 94% (0.01 secs, we should have 68.38 "only render FPS" based on this) - TCastleTransform.Render transformation: 2% - TCastleScene.Render: 38% - ShapesFilterBlending: 2% - Update: 5% - TCastleSceneCore.Update: 0% - Other: -------------------- FrameProfiler end
The frame creation time is divided into 4 stages:
- BeforeRender – time to prepare resources before rendering
- Render – rendering time
- Update – execution time of the Update function (including physics, animations, etc.)
- Other – user measurements performed outside of Update, Render, BeginRender
Starting FrameProfiler
To enable FrameProfiler, just add the CastleTimeUtils
module to the uses section and use the FrameProfiler
singleton:
FrameProfiler.Enabled := true;
Measuring the time of the physics step
When PR #144 will be merged, FrameProfiler will have an additional “Update Kraft Physics” line showing the time to complete the physics step:
-------------------- FrameProfiler begin Frame time: 0.02 secs (we should have 64.29 FPS based on this): - BeforeRender: 0% - Render: 94% (0.01 secs, we should have 68.38 "only render FPS" based on this) - TCastleTransform.Render transformation: 2% - TCastleScene.Render: 38% - ShapesFilterBlending: 2% - Update: 5% - TCastleSceneCore.Update: 0% - Update Kraft Physics: 2% (0.00037 secs) - Other: -------------------- FrameProfiler end
Own measurements in FrameProfiler
The information returned by FrameProfiler applies to all objects, if we want to measure the time of execution of a specific type or function we can do it using FrameProfiler.Start
/FrameProfiler.Stop
with a text identifier e.g.
If you have a player class TMyPlayer
implemented as a class inheriting from TCastleScene
and you want to check duration of the Update function, you can do it as follows:
TMyPlayer.Update(const SecondsPassed: Single; var RemoveMe: TRemoveType); begin FrameProfiler.Start('TMyPlayer.Update'); // TMyPlayer update code FrameProfiler.Stop('TMyPlayer.Update'); end;
Then the log will look like this:
-------------------- FrameProfiler begin Frame time: 0.01 secs (we should have 84.17 FPS based on this): - BeforeRender: 0% - Render: 13% (0.00 secs, we should have 655.95 "only render FPS" based on this) - TCastleTransform.Render transformation: 0% - TCastleScene.Render: 3% - ShapesFilterBlending: 0% - Update: 86% - TCastleSceneCore.Update: 0% - TMyPlayer.Update: 85% - Other: -------------------- FrameProfiler end
Currently, the engine allows you to make up to 16 own measurements, which is certainly enough.
Optimizations
Once you know the location of the bottleneck, you know exactly what to optimize. You can find a lot of useful information about optimizations here.