Debugging OpenGL issues in Minecraft mods using apitrace
In the transition of Minecraft version 1.14 to 1.15, Mojang introduced some sweeping changes to the way rendering is performed; while the internal code still relies on GL1-era immediate-mode, block and entity renderer classes now provide their vertices to a specific RenderLayer* which are later rendered in ordered batches.
These changes broke a majority of Minecraft mods; in the process of porting a mod to 1.15, I had to frequently rely on a tool called “apitrace”, and I thought a quick how-to might come in handy for others struggling with similar problems. Apitrace allows capturing every OpenGL call an application makes, and later replaying these calls and inspecting the entire GL state machine at each rendering step.
For this tutorial, I am using the MultiMC launcher.
First step: Install apitrace
Some operating systems already provide binaries for Apitrace, for everyone else the instructions to build Apitrace from source can be found here.
sudo dnf install apitrace apitrace-gui
pacman -S apitrace
For Windows you can get precompiled builds from here. Then add the bin folder from apitrace to the
PATH environment variable. The added path should look something like this:
Second step: Load apitrace into Minecraft
Next, we need to define the wrapper command that will start Minecraft with tracing enabled:
apitrace trace --output minecraft.trace --api gl
In MultiMC, edit your instance and click on the Settings tab, then on the Custom Commands tab on the right and tick the check box. Now provide the wrapper command from above, like so:
That’s it for setup, now you can launch the instance as usual. For debugging specific issues, I would recommend preparing a world save that you can quickly load to cause the issue, then close Minecraft again. In general you want to leave it running as little as possible, because every rendered frame is recorded.
When you have successfully reproduced the issue and closed Minecraft, open your instance’s
.minecraft folder, where you will find a file named
Open this file with the apitrace-gui (
qapitrace) you installed earlier, and now you can inspect every frame, GL call by GL call:
I will not include an in-depth tutorial on apitrace itself here, as there are plenty on the web already. If you’re new to this tool, play around a bit: Right click a GL call and select Lookup State to inspect state settings, bound textures/framebuffers etc. right up until after this GL call was executed.
One more tip though: Combing through thousands of GL calls can be confusing, and
println() calls will not show up. There is however an analogue to printf-style debugging:
/* imports */ import org.lwjgl.opengl.GREMEDYStringMarker; /* [...] */ GREMEDYStringMarker.glStringMarkerGREMEDY("ignoring lighting"); /* render code */ GREMEDYStringMarker.glStringMarkerGREMEDY("rendering a quad"); /* more render code */
I recommend using my utility library/mod TraceUtil, which just by dropping it into your mods folder, will give you some automatic annotations to common Minecraft renderpaths and also allow you to insert custom strings without the
*Classname provided by yarn
Thanks to @march for the Arch and Windows install steps.