logo
Expand description

Supported Features:

  • global_loader: Include all mechanisms necessary for calling GL using global functions.
  • struct_loader: Include all mechanisms necessary for calling GL as methods on a struct.
  • debug_trace_calls: if cfg!(debug_assertions), any call to a GL function will trace! what was called and with what args.
  • debug_automatic_glGetError: If cfg!(debug_assertions), this will automatically call glGetError after every call to any other GL function. If an error code occurs it’s shown via error! along with the name of the fn that had the error.
  • log: imports trace! and error! macros from the log crate. Otherwise they just call println! and eprintln! respectively.
  • chlorine: gets all C types from the chlorine crate (which is no_std friendly). Otherwise they will be imported from std::os::raw.
  • bytemuck: Adds support for the bytemuck crate, mostly in the form of bytemuck::Zeroable on GlFns.
  • inline: Tags all GL calls as #[inline].
  • inline_always: Tags all GL calls as #[inline(always)]. This will effectively override the inline feature.

The crate is no_std friendly by default, but features above can end up requiring std to be available.

GL Loaders

The docs for this crate hosted on docs.rs generate both the global_loader and struct_loader documentation for sake of completeness.

However, you are generally expected to use only one loader style in any particular project.

Each loader style has its own small advantages:

  • The global_loader stores the GL fn pointers in static AtomicPtr values.
    • Call load_global_gl_with to initialize the pointers.
    • Each GL fn is available as a global fn under its standard name, eg glGetError().
    • This lets you call GL functions from anywhere at all, and it’s how you might expect to use GL if you have a C background.
    • Being able to call GL from anywhere makes it easy to write Drop impls, among other things. In both styles, if you call a fn that isn’t loaded you will get a panic. This generally only happens if the context doesn’t fully support the GL version. You can check if a GL command is loaded or not before actually calling it by adding _is_loaded to the name of the command. In other words, glGetError_is_loaded to check if glGetError is globally loaded, and gl.GetError_is_loaded to check if it’s loaded in a GlFns. All of the “_is_loaded” functions are hidden in the generated docs just to keep things tidy, but they’re there.

Safety

In general, there’s many ways that GL can go wrong.

For the purposes of this library, it’s important to focus on the fact that:

  • Initially all functions are None pointers. If a fn is called when it’s in a None state then you’ll get a panic (reminder: a panic is safe).
  • You can load pointers from the current GL context (described above).
    • These pointers are technically context specific, though in practice different contexts for the same graphics driver often all share the same fn pointers.
    • The loader has no way to verify that pointers it gets are actually pointers to the correct functions, it just trusts what you tell it.
  • Since loading a fn pointer transitions the world from “it will definitely (safely) panic to call that GL command” to “it might be UB to call that GL command (even with the correct arguments)”, the act of simply loading a fn pointer is itself considered to be unsafe.
  • Individual GL commands are generally safe to use once they’ve been properly loaded for the current context, but this crate doesn’t attempt to sort out what is safe and what’s not. All GL commands are blanket marked as being unsafe. It’s up to you to try and manage this unsafety! Sorry, but this crate just does what you tell it to.

Re-exports

pub use global_commands::*;

Modules

Contains functions for using the global GL loader.