The new re­lease brings Py­thon bind­ings, Basis Uni­ver­sal tex­ture com­pres­sion, im­proved STL in­ter­op­er­ab­il­ity, bet­ter Uni­code ex­per­i­ence for Win­dows users, a more ef­fi­cient Em­scripten ap­plic­a­tion im­ple­ment­a­tion, single-head­er lib­rar­ies, new OpenGL driver work­arounds and much more.

STL-com­pat­ible con­tain­er classes and fur­ther work on re­du­cing com­pile times

Con­tinu­ing from Con­tain­ers::Point­er and Con­tain­ers::Op­tion­al in­tro­duced in the pre­vi­ous re­lease, the 2019.10 re­lease adds STL com­pat­ib­il­ity to its Con­tain­ers::Ar­rayView classes as well. In prac­tice this means std::vec­tor or std::ar­ray in­stances can be im­pli­citly con­ver­ted to Mag­num ar­ray views, and if you’re on the bleed­ing edge and use C++2a std::span, the con­ver­sion can go both ways:

#include <Corrade/Containers/ArrayViewStl.h> // enables implicit conversions

/* Image view backed by a std::vector */
std::vector<char> pixels = ;
MutableImageView2D image{PixelFormat::RGBA8Unorm, {32, 24}, pixels};

/* Getting the data back as a span on C++2a */
std::span<char> span = image.data();

The new re­lease also in­tro­duces a re­worked Con­tain­ers::StridedAr­rayView, now sup­port­ing mul­tiple di­men­sions and zero / neg­at­ive strides, giv­ing it a fea­ture par­ity with numpy.ndar­ray in Py­thon. It’s also get­ting used in a broad­er set of APIs, in­clud­ing MeshTools::gen­er­ateS­mooth­Nor­mals(), range-tak­ing Math::min() or the very use­ful Im­age::pixels() that gives raw typed ac­cess to pixel data, and even print them on ter­min­al:

importer.openFile("mosra.png");
Trade::ImageData2D image = importer.image2D(0);
Debug{} << Debug::color << Debug::packed << image.pixels<Color3ub>();
▓▓▓▓▓▓▓▓▓▓▓▓▒▒  ░░                  ░░▓▓▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓▒▒                        ░░░░▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓▓▓░░                          ░░▓▓▓▓▓▓▓▓
▓▓▓▓▓▓▓▓░░  ░░░░                        ▒▒▓▓▓▓▓▓
▓▓▓▓██▓▓    ░░                          ░░▓▓▓▓▓▓
██▓▓██░░          ░░▒▒▒▒▒▒▓▓░░            ▒▒██▓▓
████▓▓          ▒▒▓▓████████▓▓░░          ▒▒▓▓██
████▒▒          ▒▒▓▓▓▓██████▓▓░░          ░░▓▓██
████░░        ░░▓▓▓▓████████▓▓░░            ▒▒██
████░░        ░░▓▓▓▓▓▓████▓▓▓▓░░            ░░▓▓
██▓▓          ░░░░▒▒▓▓▓▓▓▓▓▓▒▒░░              ▓▓
██▓▓        ░░        ░░▒▒░░                  ▓▓
██▓▓        ▒▒▓▓░░░░  ░░▓▓                    ▓▓
▓▓▒▒        ░░▓▓▒▒▒▒▒▒▓▓▓▓                    ▒▒
▓▓          ░░▒▒▓▓▒▒▒▒████░░                  ░░
              ▒▒▒▒▒▒▒▒▓▓▓▓░░                    
              ░░▒▒▓▓▒▒░░░░                      
              ░░▒▒▓▓▓▓▒▒░░░░                    
                ░░░░░░░░░░                      
                  ░░                            
                    ░░░░                        
                                                
                                                
                                                

All this in­ter­op­er­ab­il­ity how­ever doesn’t mean all head­ers sud­denly need to #include <vector> or the like. On the con­trary — the con­ver­sion is en­abled by in­clud­ing ded­ic­ated head­ers lis­ted be­low, to­geth­er with the abil­ity to for­ward-de­clare some STL types when you don’t need the full defin­i­tion. Put all to­geth­er, this means the code both com­piles faster (when you don’t need to use STL types) and can in­ter­op­er­ate with STL types bet­ter (when you ac­tu­ally want that).

New power-ef­fi­cient ap­plic­a­tion im­ple­ment­a­tion for Em­scripten

While all Mag­num ap­plic­a­tions his­tor­ic­ally de­faul­ted to re­draw­ing and mak­ing the CPU busy only when needed in or­der to save power, this was not really the case on the web. Con­trib­uted by @Squareys, there’s a new Plat­form::Em­scrip­tenAp­plic­a­tion that aims to be more ef­fi­cient and smal­ler to down­load. Be­sides that, the Em­scripten SDL “emu­la­tion” has a lot of lim­it­a­tions and hav­ing an im­ple­ment­a­tion based dir­ectly off the HTM­L5 APIs al­lows us to be more flex­ible.

The new im­ple­ment­a­tion was also used for an ex­per­i­ment in how far can Mag­num po­ten­tially get with ex­ecut­able size op­tim­iz­a­tion. A few of those op­tim­iz­a­tions already made it to 2019.10 and lots more is in the buf­fer for next re­leases — sub­scribe to mosra/mag­num#293 for up­dates.

52.1 kB 36.3 kB 35.7 kB 19.4 kB 14.7 kB 14.7 kB 14.7 kB 14.7 kB 14.7 kB 14.7 kB 226.3 kB 224.5 kB 224.5 kB 224.5 kB 83.6 kB 75.4 kB 69.3 kB 62.6 kB 56.3 kB 44.0 kB 0 50 100 150 200 250 kB Initial state Enabling minimal runtime Additional slimming flags Disabling filesystem Chopping off all C++ stream usage Enabling CORRADE_NO_ASSERT Removing a single use of std::sort() Removing one std::unordered_map Using emmalloc instead of dlmalloc Removing all printf() usage Download size (*.js, *.wasm)

Py­thon bind­ings and Ei­gen in­ter­op­er­ab­il­ity

By far the largest part of this re­lease are the new Py­thon bind­ings, made us­ing py­bind11 and avail­able through a sep­ar­ate re­pos­it­ory at https://github.com/mosra/magnum-bindings. To get a first im­pres­sions, check out how the ba­sic C++ tu­tori­als look like when re­writ­ten in Py­thon. Large ef­fort went in­to mak­ing the Py­thon API feel like Py­thon, in­clud­ing GLSL-like vec­tor swizzles:

>>> from magnum import *
>>> a = Vector4(1.5, 0.3, -1.0, 1.0)
>>> b = Vector4(7.2, 2.3, 1.1, 0.0)
>>> a.wxy = b.xwz
>>> a
Vector(0, 1.1, -1, 7.2)

The bind­ings are op­tim­ized for zero-copy data trans­fer between C++ and Py­thon us­ing CPy­thon’s Buf­fer Pro­tocol, which at the very core means the Mag­num ar­ray view classes got ex­posed as con­tain­ers.Ar­rayView, con­tain­ers.StridedAr­rayView1D etc., with sup­port for the full Py­thon sli­cing syn­tax and in­ter­op­er­ab­il­ity with numpy.ndar­ray, memoryview and oth­er views and con­tain­ers.

While NumPy is used ex­tens­ively by re­search­ers in the Py­thon world, same could be said about Ei­gen in the C++ world. In 2019.10, Ei­gen­In­teg­ra­tion joins the ranks of GlmIn­teg­ra­tion in bring­ing built­in con­ver­sion between for­eign and Mag­num math types. Goal for both is not need­ing to worry about wheth­er mat­rix is row- or column-ma­jor or which or­der qua­ternion com­pon­ents are stored in:

#include <Magnum/EigenIntegration/Integration.h>

Eigen::Vector3f a{1.0f, 2.0f, 3.0f};
Vector3 b(a);

auto c = Matrix4::rotation(Vector3(a), 35.0_degf);

Im­age API im­prove­ments

With Mut­ableIm­ageView2D and friends and new over­loads to GL::Ab­stract­Frame­buf­fer::read(), GL::Tex­ture::im­age() etc. it’s now pos­sible to read GPU im­ages in­to ex­ist­ing memory, without un­wanted large memory al­loc­a­tions hap­pen­ing in the back­ground. These new APIs are also ex­posed to Py­thon, al­low­ing for ef­fi­cient trans­fer of rendered im­ages dir­ectly in­to a memory buf­fer man­aged by a ma­chine learn­ing frame­work, for ex­ample.

Back in 2018.04, Mag­num gained backend-in­de­pend­ent pixel formats, how­ever the Com­pressed­Pixel­Format enum was quite neg­lected un­til now, sup­port­ing just ba­sic S3TC. Now it sup­ports all widely-used com­pres­sion formats — sR­GB S3TC vari­ants, one/two-chan­nel BC4 and BC5 formats, BC6h and BC7, ETC2 and EAC formats for mo­bile plat­forms, ASTC (in­clud­ing 3D and HDR) and PVRTC. On the GL side, GL::Com­pressed­Pixel­Format learned PVRTC formats as well, ex­posed the (3D) ASTC formats for WebGL, and same was done for the Vk::vk­Format() con­ver­sion util­ity. Be­sides GL and Vulkan, the Pixel­Format / Com­pressed­Pixel­Format enum doc­u­ment­a­tion now lists also cor­res­pond­ing D3D and Met­al val­ues to make it easi­er for people us­ing (or com­ing from) these backends.

These im­prove­ments are the ini­tial batch of new fea­tures be­ing ad­ded, with more fol­low­ing next — im­proved DDS sup­port (see mosra/mag­num-plu­gins#67), a KTX2 im­port­er or, for ex­ample, mip level se­lec­tion (mosra/mag­num#369).

Basis Uni­ver­sal tex­ture com­pres­sion

The main reas­on why all the above-lis­ted com­pres­sion formats were ad­ded is Basis Uni­ver­sal. It’s a suc­cessor to Crunch, open-sourced a few months ago thanks to fund­ing from Google. What makes it so re­volu­tion­al is best ex­plained by the fol­low­ing plot. I took the cov­er.jpg used on top of this art­icle and con­ver­ted it to cov­er.basis and a bunch of raw block com­pres­sion formats for com­par­is­on:

215.0 kB 1296.0 kB 269.5 kB 154.9 kB 0.0 kB 0.0 kB 242.1 kB 0.0 kB 0.0 kB 0.0 kB 508.1 kB 0.0 kB 4969.0 kB 0.0 kB 276.3 kB 1141.1 kB 0 1000 2000 3000 4000 5000 kB JPEG -> RGBA8 Uncompressed BC3 DDS -> BC3 Compressed BC3 + ETC2 + PVRTC -> BC3 Basis Universal -> BC3 File size / memory use

Be­fore Basis, you had ba­sic­ally two ways how to op­tim­ize your as­set size:

  • Either op­tim­ize stor­age size by us­ing lossy com­pres­sion (such as JPEG), but then hav­ing to fully un­com­press to RGBA8. With the 1536×864 cov­er im­age it’s a ~200 kB im­age in­flated to over 5 MB of RGBA data.
  • Or op­tim­ize GPU memory us­age by us­ing vari­ous block com­pres­sion formats (such as BC3 / DX­T5), which is only 1.3 MB of data in memory; and with a lossless com­pres­sion on top you’ll get down to a 270 kB file. How­ever, es­pe­cially on mo­bile devices, each GPU vendor sup­ports a dif­fer­ent format so you need to ship at least a BCn, ETC and PVRTC vari­ant.

With Basis Uni­ver­sal, you get the best of both worlds — data is in­tern­ally stored in a sub­set of the ETC1 block com­pres­sion format with ad­di­tion­al com­pres­sion on top, mak­ing it smal­ler than an equi­val­ent JPEG, and then you can transcode that single file to BCn, ETC2, ASTC or PVRTC de­pend­ing on what the GPU needs.

Thanks to work done by @Squareys, Mag­num sup­ports both im­port­ing (and transcod­ing to a de­sired GPU format) via the BasisIm­port­er plu­gin as well as en­cod­ing im­ages in­to the Basis Uni­ver­sal format us­ing the BasisIm­age­Con­vert­er. Com­pared to the of­fi­cial basisu tool, which works only with PNGs, the mag­num-im­age­con­vert­er util­ity sup­ports any format that Mag­num can im­port:

magnum-imageconverter image.jpg image.basis

Of course, all op­tions sup­por­ted by basisu are ex­posed to the plu­gin con­fig­ur­a­tion as well:

magnum-imageconverter image.jpg --converter BasisImageConverter \
    -c flip_y=false,threads=8 image.basis

The Tiny­Glt­fIm­port­er sup­ports Basis files through the un­of­fi­cial GOOGLE_texture_basis ex­ten­sion. There are still some fea­tures we’re wait­ing on to get merged in or­der to have a full sup­port. One of them is an abil­ity to Y-flip im­ages dur­ing transcode (in­stead of only in the en­coder, Bi­no­mi­alLLC/basis_uni­ver­sal#79), an­oth­er are build­sys­tem im­prove­ments (Bi­no­mi­alLLC/basis_uni­ver­sal#13) — right now, the soft­ware can’t be built as a lib­rary on its own and thus is im­possible to pack­age / dis­trib­ute without re­quir­ing each pro­ject to bundle it. Un­til that’s re­solved, Basis won’t be en­abled in any Mag­num pack­ages. The only ex­cep­tion is Vcp­kg, where a Basis fork, based off the above PR, is used.

Mag­num Play­er im­prove­ments

The Mag­num Play­er util­ity re­ceived quite a few new fea­tures. It can now auto­mat­ic­ally gen­er­ate smooth nor­mals for mod­els that don’t have them and you can in­spect mesh to­po­logy by se­lect­ing it us­ing a right-click.

Apart from meshes, the play­er can now also open im­ages of all types that Mag­num can im­port. This in­cludes the above-men­tioned Basis Uni­ver­sal — and the web ver­sion knows those, too, and transcodes to BCn, ETC, PVRTC, ASTC or plain RGBA de­pend­ing on what your browser sup­ports.

DART in­teg­ra­tion and an ex­ample

The DartInteg­ra­tion lib­rary, in­teg­rat­ing the DART An­im­a­tion and Ro­bot­ics Toolkit, con­trib­uted by @cost­ashatz over a year ago, now re­ceived a well-pol­ished in­ter­act­ive ex­ample. As a side dish, Cos­t­as wrote a de­tailed over­view post, ex­plain­ing both the code and the ro­bot­ics back­ground:

Us­ing DART to con­trol a ro­bot­ic ma­nip­u­lat­or »
Gues post by Kon­stanti­nos Chatzily­ger­oud­is

Build­sys­tem us­ab­il­ity im­prove­ments

The 2019.10 re­lease irons out the re­main­ing pain points in us­ing Mag­num lib­rar­ies as CMake sub­pro­jects. All bin­ar­ies are now put in­to a com­mon dir­ect­ory in­side the build dir, which means no hassle with DLL paths on Win­dows any­more — and to help the com­mon use cases even fur­ther, SDL and GLFW DLLs are auto­mat­ic­ally copied there as well.

Plu­gin us­age with CMake sub­pro­jects is sig­ni­fic­antly im­proved too. Dy­nam­ic plu­gin bin­ar­ies are put in a cent­ral place in the build dir­ect­ory and the plu­gin man­agers now look for them re­l­at­ively to loc­a­tion of giv­en plu­gin in­ter­face lib­rary, re­mov­ing the need to in­stall everything first.

set(WITH_TINYGLTFIMPORTER ON)
set(WITH_STBIMAGEIMPORTER ON)
add_subdirectory(magnum-plugins)

Note that the above bumped the min­im­al CMake ver­sion re­quire­ment from 3.1 to 3.4, al­though we don’t ex­pect any is­sues as the ver­sions cur­rently in wide­spread use is 3.5. In any case, you can al­ways down­load a pre­b­uilt ver­sion for your plat­form.

Thanks to ex­tens­ive feed­back from @alan­jfs, the Get­ting Star­ted Guide got re­writ­ten and is now easi­er to fol­low by first-time users on Win­dows, not re­quir­ing any­body to fiddle with %PATH% or in­stalling things to ran­dom places any­more.

Win­dows-spe­cif­ic good­ies

Com­pared to 2019.01, there’s an of­fi­cial sup­port for MS­VC 2019. The com­piler still needs a few work­arounds com­pared to GCC / Clang, but it’s re­l­at­ively minor things that should not af­fect us­ab­il­ity. Ex­tra­pol­at­ing fur­ther, we ex­pect the next ver­sion of MS­VC to be fully con­form­ing, and thus not need­ing any com­piler-spe­cif­ic hand­ling. We’re com­mited to fully sup­port­ing all pre­vi­ous ver­sions back to MS­VC 2015 for the fore­see­able fu­ture.

Cor­rade::Main is a new lib­rary that, on Win­dows, adds a shim around your main() func­tion, sets up UTF-8 ter­min­al en­cod­ing, en­ables AN­SI col­or es­cape codes and con­verts Uni­code com­mand-line ar­gu­ments to UTF-8 as well, en­abling you to use the same stand­ards-con­form­ing code on all plat­forms. Ad­di­tion­ally, it’ll also al­low you to hide the ter­min­al win­dow lurk­ing in back­ground without for­cing you to im­ple­ment WinMain(). With CMake, this is all you need to do:

find_package(Corrade REQUIRED Main)
add_executable(my-application WIN32 main.cpp) # WIN32 turns it into a GUI app
target_link_libraries(my-application PRIVATE Corrade::Main)

An­oth­er thing worth men­tion­ing is that Plat­form::Sdl2Ap­plic­a­tion and Plat­form::GlfwAp­plic­a­tion now have ba­sic DPI aware­ness on Win­dows, catch­ing up with oth­er plat­forms.

Single-head­er lib­rar­ies

Start­ing with this re­lease, a sub­set of Mag­num func­tion­al­ity is be­ing ex­posed through single-head­er lib­rar­ies over at https://github.com/mosra/magnum-singles. These are all gen­er­ated from multi-file sources and thus con­tain the best of both worlds — small foot­print of the gen­er­ated files as all doc­u­ment­a­tion, com­ments and non-es­sen­tial fea­tures are stripped out, but on the oth­er hand they in­her­it ex­tens­ive doc­u­ment­a­tion and >95% test cov­er­age of the ori­gin­al source code.

The lib­rar­ies were gradu­ally in­tro­duced in the past posts, here’s the whole list:

Lib­rary LoC PpLoC1 De­scrip­tion
Cor­rade­Ar­rayView.h 644 2489 Con­tain­ers::Ar­rayView and StaticAr­rayView, light­weight al­tern­at­ives to std::span
Cor­radeStridedAr­rayView.h 5942 2923 Con­tain­ers::StridedAr­rayView, light­weight al­tern­at­ive to pro­posed std::md­span.
Cor­rade­Ar­ray.h 6982 3344 Con­tain­ers::Ar­ray and StaticAr­ray, light­weight al­tern­at­ives to std::vec­tor and std::ar­ray
Cor­rade­Op­tion­al.h 330 2736 Con­tain­ers::Op­tion­al, a light­weight al­tern­at­ive to std::op­tion­al
Cor­rade­Point­er.h 263 2312 Con­tain­ers::Point­er, a light­weight al­tern­at­ive to std::unique_ptr
Cor­radeRefer­en­ce.h 115 1626 Con­tain­ers::Ref­er­en­ce, a light­weight al­tern­at­ive to std::ref­er­en­ce_wrap­per
Cor­ra­de­Scope­Guard.h 131 34 Con­tain­ers::Scope­Guard, al­tern­at­ive to std::unique_ptr with a cus­tom de­leter
Cor­radeStlFor­wardAr­ray.h 67 24363 For­ward de­clar­a­tion for std::ar­ray
Cor­radeStlFor­ward­String.h 74 48 For­ward de­clar­a­tion for std::string
Cor­radeStlFor­wardTuple.h 78 1601 For­ward de­clar­a­tion for std::tuple
Cor­radeStlFor­ward­Vec­tor.h 62 7663 For­ward de­clar­a­tion for std::vec­tor
Cor­radeStl­Math.h 57 29704 Like #include <cmath>, but without the heavy C++17 ad­di­tions
1.
^ lines of code after a pre­pro­cessor run, with sys­tem in­cludes ex­pan­ded. Gathered us­ing GCC 9.2 and lib­stdc++, un­less said oth­er­wise.
2.
^ a b not a total size due to inter-lib­rary de­pend­en­cies
3.
^ a b gathered us­ing Clang 9.0 and libc++, since lib­stdc++ doesn’t have a for­ward de­clar­a­tion for std::ar­ray / std::vec­tor
4.
^ gathered us­ing GCC 9.2, lib­stdc++ and -std=c++17

Test­Suite im­prove­ments, shader test­ing

If you’re not yet us­ing Test­Suite for tests in your Mag­num-based pro­ject (well, or any oth­er), con­sider giv­ing it a try. For this re­lease, con­tin­ued ef­fort was put on render out­put test­ing — De­bug­Tools::Com­pareIm­age re­ceived an abil­ity to save a dia­gnost­ic file in case of a com­par­is­on fail­ure, and can com­pare against an ar­bit­rary pixel view in ad­di­tion to files and Im­ageView in­stances. Tests can be now also run with verb­ose out­put, show­ing de­tailed info even in case the com­par­is­on passes:

./ShadersPhongGLTest -v --only 38
Starting Magnum::Shaders::Test::PhongGLTest with 1 test cases...
  INFO [38] renderShininess(80) at src/Magnum/Shaders/Test/PhongGLTest.cpp on line 966
        Images Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()) and Utility::Directory::join({_testDir, "PhongTestFiles", data.expected}) have deltas 1.66667/0.0159375 below threshold 12/0.043. Delta image:
          |                                        |
          |                                        |
          |                                        |
          |       ::     :                         |
          |      Z:     :::                        |
          |    :Z        Z                         |
          |    ::   Z :  :Z:                       |
          |    Z   :Z:   Z:       :                |
          |   ::   + : : :                         |
          |     :  :  :  :     ::    :             |
          |          :               Z             |
          |        +::   :        : Z    :         |
          |   :     ++:: ZZ :   +Z::   : ::        |
          |        +ZZ: +:  :     :     Z:         |
        Top 10 out of 189 pixels above max/mean threshold:
          [19,23] #f96161, expected #fa6363 (Δ = 1.66667)
          [20,23] #ffa9a9, expected #ffabab (Δ = 1.33333)
          [21,22] #ffd9d9, expected #ffdbdb (Δ = 1.33333)
          [20,22] #ff9090, expected #ff9292 (Δ = 1.33333)
          [13,62] #250707, expected #260808 (Δ = 1)
          [28,56] #2a0808, expected #2b0909 (Δ = 1)
          [11,56] #4d0f0f, expected #4e1010 (Δ = 1)
          [31,54] #2a0808, expected #2b0909 (Δ = 1)
          [19,54] #490f0f, expected #480e0e (Δ = 1)
          [ 8,51] #6b1515, expected #6c1616 (Δ = 1)
Finished Magnum::Shaders::Test::PhongGLTest with 0 errors out of 2 checks.

With these im­prove­ments in place, the whole Shaders lib­rary has tests for ren­der­ing out­put. So far, thanks to these, we ironed out a bunch of bugs in dusty corner cases, but that’s not all — it makes fur­ther modi­fic­a­tions, op­tim­iz­a­tions and im­prove­ments easi­er to make as re­gres­sions will now be caught through auto­mat­ic test­ing.

Re­duced over­head, guar­an­teed thread safety and unique­ness of glob­als

While glob­als are of­ten a source of im­mense pain, some­times hav­ing a state glob­al is the most prag­mat­ic de­cision of all. Mag­num cur­rently uses glob­als in these few places:

  1. Util­ity::De­bug scoped out­put re­dir­ec­tion and col­or­ing
  2. Each com­piled-in Util­ity::Re­source re­source re­gisters it­self in­to a glob­al stor­age
  3. Sim­il­arly, stat­ic plu­gins re­gister them­selves in­to Plu­gin­Man­ager
  4. And be­cause OpenGL (and then Open­AL, which is mod­elled after it) has a glob­al con­text, it makes sense to have cur­rent GL::Con­text / Au­dio::Con­text glob­ally ac­cess­ible as well

One oth­er us­age of glob­als was in Re­source­M­an­ager (and trans­it­ively in De­bug­Tools::Ob­jectRender­er as well), but those APIs are now de­prec­ated in fa­vor of ex­pli­citly passed ref­er­ences. And, for the up­com­ing Vulkan backend, there’s no plan to have a GL-like “glob­al con­text” at all.

For this re­lease, all glob­al state was re­writ­ten to be com­pletely al­loc­a­tion-free (re­gis­tra­tion of re­sources and stat­ic plu­gins is now just build­ing an in­trus­ive linked list), which means there’s no need to run any glob­al de­struct­ors for these. Moreover, while already very light­weight, the auto­mat­ic re­gis­tra­tion can be com­pletely op­ted out of, al­low­ing you to get rid of glob­al con­struct­ors as well.

All glob­al state that’s read-write is now made thread_local, mean­ing every thread will have its own copy of the glob­al data. This makes more sense than hav­ing the glob­al state ac­cess guarded by a lock. Be­sides be­ing faster, you might want to re­dir­ect your log out­put to a file in one thread but not in the oth­er. Apart from these, Mag­num doesn’t do any­thing about thread­ing on its own — if your app needs to share data across threads, you’re fully re­spons­ible for guard­ing against data races. Thread-loc­al vari­ables of course come with some small over­head, and if you don’t need that, you can turn it off via the COR­RADE_BUILD_MUL­TI­TH­READED op­tion.

With the in­tro­duc­tion of Py­thon bind­ings, glob­als posed an­oth­er prob­lem — if Mag­num is built stat­ic­ally and then linked in­to two dis­tinct Py­thon mod­ules, the glob­als get du­plic­ated, each mod­ule hav­ing its own copy. On Unix sys­tems this was eas­ily solved by mark­ing the few glob­als ex­por­ted weak sym­bols, telling the dy­nam­ic linker to al­ways pick only one of them. On Win­dows there’s no no­tion of a weak link­ing and ad­di­tion­ally __declspec(dllexport) at­trib­utes can’t be thread_local, so this got solved by a brown ma­gic in­volving Get­P­ro­c­Ad­dress().

Full changelog … and what’s next?

This re­lease took al­most 9 months to make, much more than ini­tially planned, and a “re­lease cut” had to be made in or­der to keep it from grow­ing in­def­in­itely. Be­cause of that, there’s a lot of things that didn’t fit in­to this an­nounce­ment and the changelogs are lar­ger than you might ex­pect:

For the next ver­sion, apart from im­age-re­lated im­prove­ments hin­ted above, well un­der­way is a re­work of Trade::Mesh­Data3D, with sup­port for more ver­tex at­trib­utes, ar­bit­rary data types and zero-copy data im­port. This one will likely res­ult also in ad­di­tions to Cor­rade con­tain­er types (grow­able ar­rays) and vari­ous oth­er things. Sub­scribe to mosra/mag­num#371 for up­dates.

Hav­ing Py­thon bind­ings out of the way, the Vulkan bind­ings got a pri­or­ity as well — ex­pect Vulkan-re­lated changes pop­ping up in the next months.

Up­dat­ing from pre­vi­ous ver­sions

If you’re us­ing Homebrew, MSYS pack­ages Arch­Linux AUR or Vcp­kg, 2019.10 is already in the re­pos­it­or­ies. Arch­Linux com­munity pack­ages are sched­uled for an up­date, and Ubuntu pack­ages can be built dir­ectly from with­in the cloned re­pos­it­ory as usu­al.

The lib­rary is con­stantly un­der­go­ing a “head­er hy­giene” in­clude cleanup, mean­ing you can now get com­piler er­rors re­lated to use of in­com­plete types. The fix is in most cases in­clud­ing cor­res­pond­ing head­ers — in many cases some of these:

#include <Corrade/Containers/Reference.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Utility/DebugStl.h>
#include <Magnum/Math/Matrix4.h>

Since it’s been over a year since the “GL split” in 2018.04, 2019.10 re­moves all com­pat­ib­il­ity ali­ases of GL APIs in the root namespace. If you’re up­grad­ing from older ver­sions, the re­com­men­ded way is as al­ways jump­ing over all stable re­leases (so 2018.04, 2018.10, 2019.01) and fix­ing up what breaks, in­stead of dir­ectly try­ing with the latest.

Thank you

A huge part of the work for this re­lease was done by ex­tern­al con­trib­ut­ors — sin­cere thanks to every­one (and apo­lo­gies to those I for­got):