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.
- Why creating a OSL::OCIOColorSystem instance by default? The code could delay the creation on the first request.
- Cons - It will introduce a performance hit somewhere else!
- Pros - It will do nothing if color mgt is never used.
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.
- There is no error handling i.e. OCIO throws an exception if the config is faulty, wrong version, etc. The OSL & OIIO layers must handle OCIO exceptions.
OSL and OIIO are both "no exception" APIs by design.
- I think it highlights that the color mgt in OSL must be decoupled from OIIO, and only called on explicit demand.
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.