Tips and tricks » Troubleshooting

Various tricks and solutions to common pitfalls.

Building issues

If your project suddenly stops building after a Magnum upgrade, check these things:

  • If building fails on the CMake step, be sure that you have up-to-date FindCorrade.cmake and FindMagnum.cmake CMake modules in your project. They are contained in the modules/ directory of Magnum repositories and also get installed into share/cmake/Corrade and share/cmake/Magnum.
  • In very rare cases the CMake build directory may not survive an upgrade. If you get some particularly cursed errors, try recreating it from scratch.
  • The library is constantly evolving, meaning that APIs may get deprecated and removed over time. If you upgrade to a version that deprecated a particular API you use, the code will emit a deprecation warning, suggesting a migration path. Except for rare cases, the deprecated APIs are guaranteed to stay in the codebase for a year at least (or two subsequent version releases, whichever is longer) and only then they get removed. To make sure you're no longer using any deprecated functionality, it's possible to disable the MAGNUM_BUILD_DEPRECATED CMake option when building Magnum, although for a smoother experience it's recommended to flip this option back on when upgrading. A list of deprecated APIs is maintained in the changelog.
  • In some rare cases, it's impossible to provide a deprecated migration path and an API gets changed in a backwards-incompatible manner, directly leading to a compile error. Another possibility is that transitive header dependencies got cleaned up for speeding up compilation and you're now missing an #include. The major compatiblity breakages are always listed in the changelog.
  • If you upgrade from a really old release, it's recommended to gradually upgrade over tagged versions of Magnum and not jumping directly to latest version. That way you're more likely to follow the deprecation path, instead of directly ending up with long-deprecated APIs being gone with no direct way to know what should be used instead. If in doubt, browse the old changelogs.

Runtime issues

Magnum makes heavy use of assertions to catch programmer errors (as opposed to runtime or data-dependent errors, which get handled in more graceful ways), and because past experience showed their usefulness, majority of assertions is by default kept even in release builds.

If your application abruptly exits, it's important to know whether it was a regular exit, an abort or a crash, as each of these may point to a different problem.

  • Except for crashes, in which case the application usually won't even have a chance to complain about anything, you should get a message on the standard error output:
    • On Unix systems the output can be seen when running from a console
    • On Windows, if you don't see the console, switch the build back to a console app instead of a GUI app — in case of CMake you can temporarily remove the WIN32 part from your add_executable() call
    • On Android you can use logcat
    • On Emscripten the output is printed to the browser console
  • A regular exit may happen during startup due to an error in arguments passed on the command line, or when a window / context creation fails. The error output should mention what happened.
  • An abort is an assertion failure, with the error message telling you why. It's an abort in order to trigger a debugger break (or the assertion dialog on Windows) or create a core dump (on Unix systems) so you can see the backtrace leading to the error.
    • One of the more frequent assertion messages is GL::Context::current(): no current context. This happens when you try to use OpenGL functionality when the OpenGL context is not yet created (or no longer exists). See Delayed context creation and NoCreate constructors for more information.
  • A crash is usually a memory issue. To find the root cause, by far the easiest is to hook up AddressSanitizer (-fsanitize=address on GCC, Clang and recent MSVC). It can detect out-of-bounds accesses, use-after-free, leaks and other issues and upon discovering a problem it prints a lengthy diagnostic about what happened, where does the memory come from and what code touched it and how.

OpenGL issues

If you are experiencing the so-called "black screen of death", weird behavior or crashes on GL calls, you might want to try these things:

  • Enable debug output to see more detailed errors, warnings and performance hints. You can do that easily through the --magnum-gpu-validation command-line option or an environment variable.
    • If you are on Mac, the native OpenGL implementation doesn't support this. Instead you can manually verify that no OpenGL error was emitted.
  • Check that you use only extensions that are available on your system.
  • Check that you didn't exceed any implementation-defined limit (see Magnum GL Info output for a list of all of them).
  • If using framebuffer objects, check that they are complete.
    • Rendering to three-component GL::TextureFormat works on some GPUs but not others. TO avoid platform-dependent issues, always use one-, two- or four-component formats.
  • Change framebuffer clear color to something else than black to verify that at least something is drawn. The engine sets it to 0x1f1f1f_rgbf by default to help you a bit in this regard.
  • If nothing is drawn, use GL::PrimitiveQuery to check that at least some primitives were generated. Use GL::SampleQuery to check whether fragments were drawn.
  • Verify that the mesh is properly set up — nonzero vertex/index count, matching type in buffer and vertex specification, properly set up index buffer and index count for indexed mesh. If you specified index range, be sure that all indices fall into it, otherwise you would get undefined behavior.
  • Try disabling the depth test, face culling and other renderer features that might cause fragments to be discarded.
  • Verify that your projection and transformation matrix is properly set up — try drawing points instead of triangles, to see if they are in proper places at least.
  • For custom shaders you can Validate them. Check that all used uniforms and attributes have proper locations. Try reducing it until it is able to draw something, possibly also with some simpler mesh.
  • Magnum tracks the OpenGL state to improve performance, but the tracker can get confused if you or any other library are doing OpenGL calls outside of Magnum. For that to work, you need to reset the state tracker on boundaries between 3rd party and Magnum calls into GL. The other library also needs to be aware of this fact (either setting all state explicitly every time or having similar ability to reset its state tracker), otherwise you may need to save and restore GL state manually for that library to work.

Debugging rendering

  • Use GL::TimeQuery to find hot spots in the rendering code.
  • Mark relevant parts of code to find them easier in the debugger.
  • Use ApiTrace or RenderDoc to trace the program call by call, verify buffer and texture contents, vertex binding and count of generated primitives, rendered fragments and time spent in various calls.