OCIOv2 with OSL native support, part IV, comment or discussion
The post is not a question but a comment on the current implementation in OSL of the color mgt support. I faced a problem when developing the OSL unit test framework for OCIO, and I want to share what I found, some comments and perhaps a potential solution.
When run the OCIOv2 OSL unit test, it crashes if the OCIO env. variable is defined.
The problem originates from:
-> my main program creates "OSL::ShadingSystem"
---> creating "OSL::ShadingSystemImpl"
------> creating "OSL::OCIOColorSystem"
---------> creating "OIIO::ColorConfig" which load the config pointed by the OCIO env. variable
The problem is that OIIO is embedding OCIOv1 which cannot read an OCIOv2 config. That's the perfect example to illustrate Larry concerns about cyclic dependencies. I would also say that having an hidden dependency is problematic.
My comments are:
Hoping it will help to improve OSL and / or OIIO and ultimately the OCIOv2 unit test framework :)
I'm not "justifying" necessarily, I'm just explaining how things came to be in this state.
From the beginning, OSL needed OIIO for its image handling, the TextureSystem, and also a lot of great utility code that OSL needed like ustring and TypeDesc.
Given that OIIO was a hard dependency of OSL, and also that most renderers that needed OSL probably also needed OIIO in its own right (but not the other way around -- most users of OIIO don't also need OSL), we have followed the heuristic that whenever the same functionality was needed by both packages, the easiest way to maintain it is to put it in OIIO and for OSL to use it via OIIO's public APIs, rather than replicate it in both packages (which would create double the code maintenance for developers, as well as lead to possible clashes between the packages).
OIIO already uses only a small portion of OCIO's functionality, and OSL only needs a tiny slice of that, and in fact a strict subset of what OIIO needed to expose in its public APIs for other reasons. So it really did seem much easier to just use those OIIO public APIs related to color, rather than burden OSL with having to find and use OCIO directly, and redundant code between the packages. That also lets OSL use the logic already in OIIO that handles certain common color conversions even when an OCIO config is not available.
Yeah, I think the idea was to create up front, and avoid any kind of locking during the render.
I think we could probably do it a better way -- like if the ShadingContext also held another pointer to the color system (with the true "owned" pointer still held by the ShadingSystem). During render, it would check the Context first -- no lock needed because the context is not shared between threads -- and only fall back to the ShadingSystem (and locking and creation if needed) if the context had a null colorsystem pointer. This would allow lazy creation, with locking only the first time each thread needed to do an OCIO color operation. Should be straightforward.
OSL and OIIO are both "no exception" APIs by design.
Addressed above. I think we can solve any performance problems without giving up the nice property that all the OCIO logic (and fallbacks for when OCIO is not enabled or when OCIO is there but no config is found) do not need to be duplicated and separately maintained in both projects.
Following the discussion during the TSC meeting, the add of some color mgt in the texture() method is a challenging topic (compare to adding color mgt in transformc()) even if the API change could be as simple as adding an extra optional argument to the texture() method. So, I will wait for your feedback.
Anyway the lazy creation of the color system and the improvement of the OCIO exception handling will greatly help.