Announcement: luminance-0.31, luminance-derive and luminance-glutin

Thu Aug 29 13:12:00 2019 UTC, by Dimitri Sabadie — feed

luminance has been having lots of activity lately. I’ve been working (hard) on making it to the 1.0 release for months now and came to a very important realization: lots of changes have been done and I’m still not ready to release it. I’ve kind of lost myself in the process.

This article is about two main topics:

  • The new release of luminance and its changes.
  • The introducing of ways to learn luminance (yay!).

If you don’t care about the changes, feel free to go read this to know how you can learn about luminance and graphics programming in general.


Lately, luminance has received a wide range of feature additions, bug fixes and design ideas. I’ve been wanting to release all those changes as part of the 1.0 release but the thing is: among all the changes, some have been around on the master branch for months without a proper release on… because the 1.0 milestone was not reached. People have been moving towards luminance more and more and some provided feedback about using luminance. Happy but indecisive about what to do, I faced a dilemma:

  • Either wait and release everything as part of 1.0 but eventually block people from using all the cool features of luminance because the last release on is months old.
  • Break the feature set into two releases: 1.0 for everything and 0.31 for all the new candies.

I have decided to go with the second option.


Just before writing this article, the last luminance version was 0.30 — just for the record, that version is eleven months old, ~200 commits behind master. The new and most recent version is thus 0.31 and crates got updated:

Lot of work has been accomplished and I received several contributions from people all around the globe, including PRs and issues. I’d like to remind that I appreciate both and you are really encouraged to contribute in any way you want to. Special thanks fly to:

About that last point, my Reddit and Twitter interactions about luminance have been very interesting because I got to test the water about how people feel about luminance, especially when compared to (not so) similar crates, such as [gfx], glium or even gl. I came to the realization, after reading people and what they would love to have as a graphics crate, that luminance can have the role of the easy crate, that is not necessarily the fastest but fast enough to be quickly productive. I cannot help it but keep thinking about a simple question: if some people can make games in Java or C# with a garbage collector or using old tech like OpenGL 2.1 (yes, some people still make pretty good games with that), why would one need a perfect zero-cost abstraction down-to-the-metal unsafe ultra-optimized crate to write something? See, I went round and squares about that topic, because I’ve already used luminance in several projects of mine (mostly demoscene purposes), and it just does the job. So, yes, luminance doesn’t have that cool, new and modern Vulkan-type API, I must confess. But it has its own API, which is very functional-based (see the History section of luminance for further details about that) and, to me, modern enough so that people don’t get frustrated with the overall design being too clunky.

So, yeah. I gave up on the idea of introducing backends in luminance. I really changed my mind several times about that topic and it’s actually when I read comments on Reddit about people getting confused about the direction of the crate that I made up my mind: luminance must remain simple. Having a system of backends that can be hot-switched, concurrent etc. is just going to make things hard for people to use it — and maintain it! It’s likely that I will introduce, however, feature-gates to allow to compile luminance on WebAssembly via WebGL, OpenGL ES or even Vulkan at some point, but the difference is that no backend will be implemented. That means that those feature-flags aren’t likely to be summable at first. But all of this will be done in future releases; stay tuned.

The current blog post brings a description of all the changes of luminance-0.31. It should be the last 0.*.* version before hitting the 1.0 release. To the question:

Why not releasing 1.0 directly?

I answer that the 1.0 milestone has a backlog with two major changes that will take time to implement and I think it would be a pity to postpone a lot of great changes that are already available because of two features that are yet to be implemented. The concept of versions is to allow releasing features in a structured way without having to wait too much. So here we are.

This post also show cases a small tutorial about how to get started with luminance. The very first steps you should have would be to have a look at the examples/ directory and try to play with all of the samples.

Disclaimer: the following section of this article is based on luminance’s changelog.

Bug fixes

  • Fix and remove panic! and attributeless renders.
  • Various internal bug fixes and performance improvements.
  • Fix pixel code for Format::R and Format::RG when querying a texture’s texels.

Major changes

  • Remove the concept of GTup. No code was using it and it was not really elegant.
  • Remove the uniform_interface! macro and replace it with the UniformInterface procedural derive macro.
  • Buffer mapping is now always a mut operation. That is required to lock-in the mapped slices and prevent to generate new ones, which would be an undefined behavior in most graphics backends such as OpenGL.
  • Change the framebuffer’s slots types and meanings. Those are now more natural to use (for instance, you don’t have to repeat the framebuffer’s associated types and dimensions nor even use the Texture<..> type anymore, as a type family is now used to ease the generation of color and depth slots).
  • Change the way the Vertex trait is implemented.
    • The Vertex::vertex_format method has been renamed Vertex::vertex_desc.
    • Instead of returning a VertexFormat, that method now returns a VertexDesc. Where a VertexFormat was a set of VertexComponentFormat, a VertexDesc is a set of VertexBufferDesc.
    • VertexBufferDesc is a new type that didn’t exist back then in 0.30. It provides new data and information about how a vertex attribute will be spread in a GPU buffer. Especially, it has:
      • An index, allowing to map the vertex attribute in a shader.
      • A name, used by shader programs to perform mapping.
      • An instancing parameter, used to determine whether we want vertex instancing.
      • A VertexAttribDesc, the new name of VertexComponentFormat.
    • As said above, VertexComponentFormat was renamed VertexAttribDesc.
    • Vertex attribute can now be normalized if they are signed integral or unsigned integral. That is encoded in the VertexAttribType’s integral variants.
    • A new trait has appeared: VertexAttrib. Such a trait is used to map a type to a VertexAttribDesc.
    • Vertex has zero implementor instead of several ones in 0.30. The reason for that is that VertexBufferDesc is application-driven and depends on the vertex semantics in place in the application or library.
    • Vertex semantics are introduced in this release and are represented via the Semantics trait. Implementing directly Semantics is possible, even though not recommended. Basically, Semantics provides information such as the index and name of a given semantics as long as the list of all possible semantics, encoded by SemanticsDesc.
    • Users are highly advised to look at the Vertex and Semantics proc-macro derive in the [luminance-derive] crate.
  • Revise the Tess type to make it easier to work with.
    • The Tess::new and Tess::attributeless functions were removed.
    • The TessBuilder type was added and replace both the above function.
    • That last type has a lot of methods that can be combined in different ways to build powerful situation of tessellations, among (but not limited to):
      • Normal and indexed tessellations.
      • Attributeless tessellations.
      • Tessellations with vertex instancing support.
      • Deinterleaved tessellations
      • Tessellations with support for primitive restart indexing.
    • Slicing was revised too and now has support for two new Rust operators:
      • The a ..= b operator, allowing to slice a Tess with inclusive closed bounds.
      • The ..= b operator, allowing to slice a Tess with inclusive bounds open on the left side.
    • Previously, the Tess::new associated function expected indices to be a slice of u32. This new release allows to use any type that implements the TessIndex trait (mapping a type to a TessIndexType. Currently, you have u8, u16 and u32 available.
    • Add Tess::{as_index_slice,as_index_slice_mut}. Those now enable you to conditionally slice-map the index buffer of a Tess, if it exists.
  • Add support for generic texture sampling.
    • This new feature is supported thanks to the SamplerType trait, used as constraint on the Pixel::SamplerType associated type.
    • Basically, that feature allows you to bind a Floating texture without caring about the actual type. That is especially true as you typically use sampler2D in a shader and not sampler2DRGB32F.
    • Such a feature reduces the number of combination needed to refactorize code.
  • Implement vertex attrib explicit binding. This is a huge change that is related to vertex semantics. Basically, in 0.30, you have to ensure that the layout (location = _) is correctly set to the right value regarding what you have in your Tess’ vertex buffers. That was both unsafe and terribly misleading (and not very elegant). The new situation, which relies on vertex semantics, completely gets rid of vertex locations worries, which get overrided by luminance when a shader program gets linked.
  • Change boolean-like enums — such as DepthTest — variants from Enabled / Disabled to On / Off or Yes / No, depending on the situation.
  • Move swap_buffers from GraphicsContext to Surface in [luminance-windowing].
  • Switch to GenMipmaps instead of bool to encode whether mipmaps should be generated in texture code. That change is a readability enhancement when facing texture creation code.
  • Make Dimensionable::zero_offset() a constant, Dimensionable::ZERO_OFFSET.
  • Change the way cursor modes are encoded from bool to CursorMode.

Minor changes

  • Add the [luminance-glutin] crate, the windowing crate support for glutin.
  • Add the [luminance-derive] crate.
    • That crate provides several procedural derive macros you can use to easily implement all required traits to work with luminance. Especially, some traits that are unsafe can be implemented in a safe way with that crate, so you should definitely try to use it.
    • Current available proc-macros are:
      • #[derive(Vertex)]: derive the Vertex trait for a struct.
      • #[derive(Semantics)]: derive the Semantics trait for an enum.
      • #[derive(UniformInterface)]: derive the UniformInterface trait for a struct.
  • Support for dynamic uniform queries. Those are used whenever you don’t know which variables will be used in a shader at compile-time. This might be the case if you’re writing a GUI tool or a video game that uses a custom scripting language / node-ish representation of shaders. That feature doesn’t break the already-in-place and great uniform interface but complements it. You can use a shader Program<_, _, ()> and still set uniform values by querying the uniforms dynamically. This feature also fully benefits from the strongly typed interface of Uniform<_>, so you will get TypeMismatch runtime error if you try to trick the type system.
  • Add the std feature gate, allowing to compile with the standard library – this is enabled by default. The purpose of this feature is to allow people to use default-features = false to compile without the standard library. This feature is currently very experimental and shouldn’t be used in any production releases so far – expect breakage / undefined behaviors as this feature hasn’t been quite intensively tested yet.
  • Add support for the R11FG11FB10F pixel format.
  • Migrate to Rust Edition 2018.
  • The WindowOpt now has support for multisampling. See the WindowOpt::set_num_samples for further details.
  • Implement dynamic edition of windowing types properties. That allows to change data on-the-fly, such as the cursor mode.
  • Introduce normalized texturing. That feature is encoded as pixel formats: any pixel format which symbol’s name starts with Norm is a normalized pixel format. Such formats state that the texels are encoded as integers but when fetched from a shader, they are turned into floating-point number by normalizing them. For instance, when fetching pixels from a texture encoded with R8UI, you get integers ranging in [0; 255] but when fetching pixels from a texture encoded with NormR8UI, even though texels are still stored as 8-bit unsigned integers, when fetched, you get floating-point numbers comprised in [0; 1].

Patch & misc changes

  • Remove std::mem::uninitialized references, as it is now on deprecation path. Fortunately, the codes that were using that function got patched with safe Rust (!) and/or simpler constructs. It’s a win-win.
  • Add the #[repr(C)] annotation on vertex types in examples. That is a bit unfortunate because such an annotation is very likely to be mandatory when sending data to the GPU and it should be done automatically instead of requiring the user to do it. That situation will be fixed in a next release.
  • Add more CI testing.
  • Update examples and made them available to the cargo run --example command. Read more here.
  • Massive documentation rewrite (among the use of #![deny(missing_docs)]. The situation is still not perfect and patch versions will be released to fix and update the documentation. Step by step.
  • Add design notes and documents in the repository.
  • Massive dependencies update. Special thanks to @eijebong for his help!
  • Add the 11-query-texture-texels example, which showcases how to query a texture’s texels and drop it on the filesystem.
  • Add and update README files. Especially, the gitter link was removed and an IRC link was added. If you want to get help:
    • Server:
    • Channel: #luminance

Learning luminance

I also spent quite a lot of time and energy working on two ways to learn luminance:

So far, I’m writing articles and the wiki is going to be updated let’s say, every week, if I find enough spare time. You can also tell me what kind of stuff you’d like to learn and do.

The official documentation is up to date but is not as good as I expect it to be. I will be adding patches versions to 0.31 to update it.

I hope you like luminance and will make a good use of it. And of course, keep the vibes!