Contributing

Getting started

Checking Out The Codebase

The main code repository is available on Github: http://github.com/AcademySoftwareFoundation/OpenColorIO

For those unfamiliar with git, the wonderful part about it is that even though only a limited number people have write access to the main repository, anyone is free to create, and even check in, changes to their own local git repository. Your local changes will not automatically be pushed back to the main repository, so everyone feel free to informally play around with the codebase. Also - unlike svn - when you download the git repository you have a full copy of the project’s history (including revision history, logs, etc), so the majority of code changes you will make, including commits, do not require network server access.

The first step is to install git on your system. For those new to the world of git, GitHub has an excellent tutorial stepping you through the process, available at: http://help.github.com/

To check out a read-only version of the repository (no GitHub signup required):

git clone git://github.com/AcademySoftwareFoundation/OpenColorIO.git ocio

For write-access, you must first register for a GitHub account (free). Then, you must create a local fork of the OpenColorIO repository by visiting http://github.com/AcademySoftwareFoundation/OpenColorIO and clicking the “Fork” icon. If you get hung up on this, further instructions on this process are available at http://help.github.com/forking/

To check out a read-write version of the repository (GitHub acct required):

git clone git@github.com:$USER/OpenColorIO.git ocio

Initialized empty Git repository in /mcp/ocio/.git/
remote: Counting objects: 2220, done.
remote: Compressing objects: 100% (952/952), done.
remote: Total 2220 (delta 1434), reused 1851 (delta 1168)
Receiving objects: 100% (2220/2220), 2.89 MiB | 2.29 MiB/s, done.
Resolving deltas: 100% (1434/1434), done.

Both read + read/write users should then add the AcademySoftwareFoundation/OpenColorIO main branch as a remote. This will allow you to more easily fetch updates as they become available:

cd ocio
git remote add upstream git://github.com/AcademySoftwareFoundation/OpenColorIO.git

Optionally, you may then add any additional users who have individual working forks (just as you’ve done). This will allow you to track, view, and potentially merge intermediate changes before they’re been pushed into the main trunk. (For really bleeding edge folks). For example, to add Jeremy Selan’s working fork:

git remote add js git://github.com/jeremyselan/OpenColorIO.git

You should then do a git fetch, and git merge (detailed below) to download the remote branches you’ve just added.

Reference Build Environment

To aid new developers to the project and provide a baseline standard, OCIO provides a reference build environment through Docker. Docker essentially is a container that consists of both a Linux distro and the dependencies needed to run a client application. This is typically used for deploying apps and services to servers, but we are using it to provide an isolated development environment to build and test OCIO with. With this environment you are guaranteed to be able to compile OCIO and run its non-GUI command line applications.

For more information on Docker, start here: https://docs.docker.com/engine/docker-overview/

In order to run the Docker environment you will have to build it from the Dockerfile provided in the repo directory:

OpenColorIO/shared/docker

Run this command in order to build the Docker image (aprox. 20min):

docker build . -t ocio:centos7_gcc48 -f dockerfile_centos7_gcc48

You can then mount the current OCIO directory and compile using the Docker image with:

docker run --volume $PWD/../../:/src/ociosrc -t ocio:centos7_gcc48 bash -c 'mkdir /build && cd /build && cmake /src/ociosrc && make -j2`

See also ASWF Docker for ASWF-managed docker images for building and testing OpenColorIO.

Merging changes

After you fork and clone OCIO, the upstream repository will change continually. Your fork will not receive those changes until you manually pull and push the commits, and in the case of in-progress feature branches, you’ll need to merge those changes or rebase your commits on top of them regularly to stay up to date. To update your fork from upstream run the:

git checkout main
git pull upstream main && git push origin main

The first command makes sure you have the main branch checked out, and the second combines an upstream pull (getting all the new commits to bring your local clone up to date) and an origin push (updating your fork’s remote main). Following these commands the main branch will be identical between the OpenColorIO repository and your fork.

To merge these changes into a feature branch (making the branch able to merge with the upstream main), run:

git checkout myFeature
git merge main

git will report any merge conflicts encountered and allow you to resolve them locally prior to committing the merge.

Alternatively you can rebase the changes into your branch, which will replay your branch commits on top of the latest main branch commits. A rebase should only be used if you are the only contributor to a branch. Since rebasing alters the branch’s commit history, a force push is required to push the changes to the remote repository, which can be problematic for others contributing to the same branch. To rebase, run:

git checkout myFeature
git rebase main

Follow the interactive instructions that git provides during the rebase to resolve merge conflicts at each replayed commit. Update your remote branch following a successful rebase with:

git push origin myFeature --force

There are various reasons why you might prefer a merge or a rebase. This article from Atlassian provides a great basis for understanding both options along with their benefits and trade-offs.

Repository structure

The OpenColorIO repository has a relatively straight-forward structure, and a simple branching and merging strategy.

All development work is done directly on the main branch. This represents the bleeding-edge of the project and any contributions should be done on top of it.

After sufficient work is done on the main branch and OCIO leadership determines that a release is due, we will bump the relevant internal versioning and tag a commit with the corresponding version number, e.g. v2.0.1. Each Minor version also has its own “Release Branch”, e.g. RB-1.1. This marks a branch of code dedicated to that Major.Minor version, which allows upstream bug fixes to be cherry-picked to a given version while still allowing the main branch to continue forward onto higher versions. This basic repository structure keeps maintenance low, while remaining simple to understand.

Root

The root repository directory contains two groups of files:

  1. Configuration files used by Git and other cloud services that interface with the OpenColorIO GitHub account.

  2. Important *.md documentation on the OpenColorIO project’s license, governance, and operational policies.

CMake configuration must be initiated from this directory, which is the .git root when cloning the OpenColorIO repository.

.github/workflows

This directory contains the project GitHub Actions configuration, which defines continuous integration (CI) workflows for all supported platforms. Each .yml file defines one GHA workflow, which can contain one or more jobs and the repository events that trigger the workflow.

ASWF

This subdirectory contains important ASWF governance documents like the OpenColorIO charter, CLAs and DCO reference.

The meetings subdirectory contains historical meeting minutes for TSC (Technical Steering Committee) and working group meetings. More recent TSC and working group meeting notes are stored on the ASWF Wiki.

docs

This directory contains the OpenColorIO documentation source and build configuration.

See Documentation guidelines for information on contributing to OCIO documentation.

ext

Houses modified external dependencies which are permissible to store within the OpenColorIO repository. Permissible dependencies have compatible FOSS licenses which have documented approval by the ASWF governing board.

include

This directory contains the OpenColorIO public C++ headers, which define the publicly accessible interface (API) for OCIO. This is the best ground truth reference available for developers wanting to explore an OpenColorIO implementation in their application.

share

This directory contains supplementary resources for building and using OpenColorIO. This includes scripts used by OCIO CI, CMake, and other build system and example components. Dockerfiles are provided to assist with container-based OpenColorIO builds.

The cmake subdirectory contains all CMake modules and macros used by the OCIO build system, and is the best reference for troubleshooting CMake package finding issues.

src

This directory contains the OpenColorIO source code and is broken into the following subdirectories:

  • OpenColorIO: Core library source, including all code related to transforms, ops, and file format IO.

  • apps: Source for each OCIO command-line tool or “app” (e.g. ociobakelut). These tools also provide excellent example usage of integrating the OCIO library in a C++ application.

  • apputils: Supporting utility code shared by the OpenColorIO apps.

  • bindings: OpenColorIO language bindings for Python and Java (note that the OCIO Java bindings are not actively maintained. Contributions to update this work is welcome and appreciated).

  • libutils: Supplementary and example helper libraries for integrating OpenColorIO into applications. Utilities for using OCIO with OpenGL and with OpenImageIO/OpenEXR are included.

  • utils: Common header-only utilities shared by the core OpenColorIO library and the other utility sources.

tests

This directory contains the OpenColorIO test suite, both for C++ and all supported bindings. Each core *.cpp source file has a corresponding *_tests.cpp file with all of its tests. Separate tests suites for CPU and GPU functionality are provided since a GPU may not always be available. The tests/data/files subdirectory contains a wide array of LUT files and other raw data for testing file transforms.

vendor

This directory contains source for plugins to integrate OpenColorIO into third-party software and DCCs (e.g. Photoshop). Software vendors are encouraged to contribute their OCIO integrations back to the project at this location if practical (e.g. plugin source).

Architectural notes

Coming soon…

Coding style guide

There are two main rules when contributing to OpenColorIO:

  1. When making changes, conform to the style and conventions of the surrounding code.

  2. Strive for clarity, even if that means occasionally breaking the guidelines. Use your head and ask for advice if your common sense seems to disagree with the conventions.

File conventions

C++ implementation should be named *.cpp. Headers should be named *.h.

Line length

Each line of text in your code should be at most 100 characters long. Generally the only exceptions are for comments with example commands or URLs - to make copy and paste easier. The other exception is for those rare cases where letting a line be longer (and wrapping on an 100-character window) is actually a better and clearer alternative than trying to split it into two lines. Sometimes this happens, but it’s rare.

DO NOT alter somebody elses code to re-wrap lines (or change whitespace) just because you found something that violates the rules. Let the group/author/leader know, and resist the temptation to change it yourself.

Formatting

  • Indent 4 spaces at a time, and use actual spaces, not tabs. This is particularly critical for Python code. The only exception currently allowed is within Makefiles, where tab characters are sometimes required.

  • Opening brace should go on the line following the condition or loop.

  • The contents of namespaces are not indented.

  • Function names should be on the same line as their return values.

  • Function calls should NOT have a space between the function name and the opening parenthesis. A single space should be added after each required comma.

Here is a short code fragment that shows these concepts in action:

namespace OCIO_NAMESPACE
{

int MungeMyNumbers(int a, int b)
{
    int x = a + b;

    if (a == 0 || b==0)
    {
        x += 1;
        x += 2;
    }
    else
    {
        for (int i=0; i<16; ++i)
        {
            x += a * i;
        }
    }

    return x;
}

} // namespace OCIO_NAMESPACE

Misc. rules

  • Avoid macros when possible.

  • Anonymous namespaces are preferred when sensible.

  • Variable names should be camelCase, as well as longAndExplicit.

  • Avoid long function implementations. Break up work into small, manageable chunks.

  • Use TODO: comments for code that is temporary, a short-term solution, or good-enough but not perfect. This is vastly preferred to leaving subtle corner cases undocumented.

  • Always initialize variables on construction.

  • Do not leave dead code paths around (this is what revision history is for).

  • Includes should always be ordered as follows: C library, C++ library, other libraries’ .h, OCIO public headers, OCIO private headers. Includes within a category should be alphabetized.

  • The C++ using directive is not allowed.

  • Static / global variables should be avoided at all costs.

  • Use const whenever it makes sense to do so.

  • The use of Boost is not allowed.

  • Default function arguments are not allowed.

  • Class members should start with m_ and use camelCase.

  • Public static functions should be PascalCase.

Bottom line

When in doubt, look elsewhere in the code base for examples of similar structures and try to format your code in the same manner.

Portions of this document have been blatantly lifted from OpenImageIO, and Google.

Unit tests

All functionality in OpenColorIO must be covered by an automated test. Tests should be implemented in a separate but clearly associated source file under the tests subdirectory (e.g. tests for src/OpenColorIO/Context.cpp are located in tests/cpu/Context_tests.cpp). This test suite is collectively expected to validate the behavior of every part of OCIO:

  • Any new functionality should be accompanied by a test that validates its behavior.

  • Any change to existing functionality should have tests added if they don’t already exist.

The test should should be run, via ctest, before submitting a pull request. Pull requests will not be merged until tests are present, running and passing as part of the OpenColorIO CI system.

For verbose test output (listing each test and result status), run:

ctest -V

Test framework

C++

The OCIO C++ test framework is based on the OpenImageIO test framework.

The macros defined in UnitTest.h are used to define tests and assert expected behavior:

  • OCIO_ADD_TEST: Define a test and add it to the named test group. Added tests will execute whenever ctest is run. Test groups and names should be clearly named for logical test execution and identification of failures that occur.

  • OCIO_CHECK_*: Macros for assertion of expected test results and behavior. Checks are provided for result comparison, exception handling, and various degrees of numeric precision validation.

C++ unit test source files are organized into the following subfolders:

  • apphelpers: Tests for utilities in src/libutils/apphelpers.

  • cpu: Main OCIO library tests, including functionality which utilizes the CPU renderer.

  • gpu: GPU-specific tests, which must be run on supported graphics hardware. GPU tests are gated behind a dedicated CMake option OCIO_BUILD_GPU_TESTS (which is ON by default).

  • utils: Tests for utilities in src/utils.

Python

The OCIO Python test suite uses the Python-bundled unittest framework. Each bound class has a dedicated TestCase class with a test_* method per specific test.

Test cases must be imported into OpenColorIOTestSuite.py and added to the suite method to be included in ctest execution.

Java

The OCIO Java test suite uses the JUnit framework. Each bound class extends the TestCase class with individual assertions begin defined in a single test_interface method.

Note

The OCIO Java bindings have not been actively maintained so the test suite is incompatible with the current OpenColorIO API. Contributions to restore support for Java in OCIO are welcome. See GitHub issue #950 for more information.

Issues

Please visit http://github.com/AcademySoftwareFoundation/OpenColorIO/issues for an up to date listing of bugs, feature requests, etc.

See the “Good first issue” label for good issues for new contributors to OpenColorIO.

Submitting an issue

To submit a feature request or defect/bug, visit the OCIO GitHub issues page and click the “New Issue” button.

For bug reports, include detailed information on your environment, including OCIO version or branch, OS version, compiler version, and complete steps to reproduce the issue. Small self-contained code snippets should be included to help reproduce code-related defects.

If the issue you are reporting is related to a security vulnerability, please follow the reporting procedures outlined in the OpenColorIO security policy.

Submitting Changes

Code Review

Ask early, and ask often!

All new contributors are highly encouraged to post development ideas, questions, or any other thoughts to Slack or the Mailing Lists before starting to code. This greatly improves the process and quality of the resulting library. Code reviews (particularly for non-trivial changes) are typically far simpler if the reviewers are aware of a development task beforehand. (And, who knows? Maybe they will have implementation suggestions as well!)

Development and Pull Requests

This will outline the general mechanics of working with git and GitHub to successfully contribute to the project. If any of the terms used are unfamiliar to you please do a quick search and then ask any of the contributors for assistance.

Tip

There’s an excellent tutorial demonstrating how to contribute to an OSS GitHub project on Rob Allen’s DevNotes. It is highly recommended to give this post a read prior to cloning the OpenColorIO repository if you intend to contribute.

  • Fork the AcademySoftwareFoundation/OpenColorIO repository

  • Clone your fork to your local workspace:

    git clone https://github.com/$USER/OpenColorIO.git
    
  • cd into the cloned directory

  • Connect your cloned repo to the original upstream repository as a remote:

    git remote add upstream https://github.com/AcademySoftwareFoundation/OpenColorIO.git
    
  • You should now have two remotes:

    git remote -v
    origin https://github.com/$USER/OpenColorIO (fetch)
    origin https://github.com/$USER/OpenColorIO (push)
    upstream https://github.com/AcademySoftwareFoundation/OpenColorIO (fetch)
    upstream https://github.com/AcademySoftwareFoundation/OpenColorIO (push)
    
  • Pull the latest changes from upstream:

    git checkout main
    git pull upstream main
    
  • Create a branch for your contribution:

    git checkout -b myFeature
    
  • Check if it successfully compiles and passes all unit tests

  • Commit your changes. The -s option will sign-off your commit, which is a requirement for contributing to OpenColorIO. Every commit MUST be signed-off by someone authorized to contribute under a current ICLA or CCLA:

    git add .
    git commit -s -m 'Implement my feature'
    
  • If your PR changes anything that appears in the public API documentation, you should follow the directions below in “Updating the Python docs”. If this proves problematic for you, please reach out for help on Slack. One of the other developers will probably be able to make the updates for you in another PR.

  • Push your changes back to origin (your fork):

    git push -u origin myFeature
    
  • Ensure that all CI tests complete on GitHub actions

  • Visit your fork in a web browser on github.com

  • When ready click the “New pull request” button, make sure it can merge, and add appropriate comments and notes. GitHub will also provide a convenient “Compare & pull request” button for recent pushes to streamline this step.

  • Wait for code review and comments from the community.

  • At various points in the review process other pull requests will have been merged into OpenColorIO main, at which point merging of your PR will be blocked with the message “This branch is out-of-date with the base branch”. Clicking the “Update branch” button will automatically merge the updated branch into your feature branch. This step may need to be repeated multiple times depending on current commit activity.

See CONTRIBUTING.md for more information.

Documentation guidelines

OpenColorIO is documented using reStructuredText, processed by Sphinx.

The documentation primarily lives in the docs/ folder, within the main OpenColorIO repository.

The rST source for the C++ API documentation is extracted from comments in the public header files in include/

Installation of requirements

Scripts are available, for each platform, to install the documentation requirements.

The install_docs_env.sh script in the share/ci/scripts/<Platform> directory will install the Python-related requirements for building the documentation (Sphinx, six, testresources, recommonmark, sphinx-press-theme, sphinx-tabs, and breathe) and Doxygen.

Use GitBash (provided with Git for Windows) to execute the script on Windows.

Python 3 is required to build the documentation. If you have multiple Python installs you’ll need to make sure pip and CMake find the correct version. You can manually inform CMake of which to use by adding this option to the below cmake command, which configures the documentation build:

-DPython_ROOT=<Path to Python 3 root directory>

For the Python packages, ensure their locations are in your PYTHONPATH environment variable prior to configuring the build.

Building the docs

The build is just like a regular build from source, but specify the -D OCIO_BUILD_DOCS=ON argument to CMake.

Then run the make docs target. The default HTML output will be created in build_dir/docs/build-html/

Note that CMake must be run before each invocation of make to copy the edited rST files.

Initial run:

$ mkdir build && cd build

Then after each change you wish to preview:

$ cmake -D OCIO_BUILD_DOCS=ON .. && make docs

Updating the Python docs

If a contributor makes changes to any part of OCIO which affects the Python API docs (so, public headers, Python bindings, any documentation process code, etc.) they should do a local build with the new CMake option -DOCIO_BUILD_FROZEN_DOCS=ON, and add the modified rST files under docs/api/python/frozen to their PR.

Note: If you run the scripts on Linux, the freezing process should work well. On other platforms, the process may sometimes make spurious deltas to rST files unrelated to your changes. Please don’t add these files to your PR.

The OCIO conf.py module has a switch that detects when docs are being built on GH Actions (CI env var == true) it will backup the frozen folder to a sibling backup folder on Sphinx init, and following Sphinx build completion will do a file-by-file comparison of the new frozen and the backup folders. If there are differences, the CI job may fail with an error explaining where the differences were found and with instructions on how to fix them.

The conf.py also has a switch that detects when it is being run on RTD, and in that case will itself run Doxygen to generate the XML needed by breathe prior to building the docs, and will also facilitate a CMake configure_file-like process (via Python) to handle substitutions in headers and docs source files that CMake would usually handle, but can’t in this case. One potential plus to all of this is that if someone wants to just build OCIO docs, they can technically do so by running sphinx-build in the docs directory, and nothing more. Right now that only works when the READTHEDOCS env var == True, but it could be easily exposed another way if needed.

These features required several custom Sphinx extensions tuned for our project which are located under share/docs.

Building the docs – Excluding the API docs

If you don’t need to build the API documentation, there is a quick and dirty way to do a docs build. This approach does not need to compile the C++ code but is not ideal since it modifies files in the source directory rather than the build directory:

export READTHEDOCS=True cd docs (in the source directory) mkdir _build sphinx-build -b html . _build <your web browser name> _build/index.html

Basics

  • Try to keep the writing style consistent with surrounding docs.

  • Fix all warnings output by the Sphinx build process. An example of such an warning is:

    checking consistency... [...]/build/docs/userguide/writing_configs.rst:: WARNING: document isn't included in any toctree
    
  • Use the following hierarchy of header decorations:

    Level 1 heading
    ===============
    
    Level 2 heading
    ***************
    
    Level 3 heading
    +++++++++++++++
    
    Level 4 heading
    ---------------
    
  • To add a new page, create a new .rst file in the appropriate location. In that directory’s index.rst, add the new file to the toctree directive.

    The new file should contain a top-level heading (decorated with ===== underline), and an appropriate label for referencing from other pages. For example, a new file docs/userguide/baking_luts.rst might start like this:

    .. _userguide-bakingluts:
    
    Baking LUT's
    ============
    
    In order to bake a LUT, ...
    

Quirks

The vuepress theme that we’ve migrated to has some quirks to its design. For example, it only allows two nested table of contents (TOC). So things have to be organized in a slightly different way than other sphinx projects.

The root-level toc_redirect.rst points to where to find the different section TOCs. The name and contents of each sections TOC is defined in that sub-directory’s _index.rst file.

In this TOC the :caption: directive determines what the name of the section will be in the sidebar, and in the header of the website. The H1 header determines the name of the page in the right/left arrows navigation bar. In a lot of cases this ends up doubling up the name on the page, but this seems unavoidable at the present time. If additional explanatory text is put in the _index.rst files then it shouldn’t be as problematic.

The site will show all H1 headers in the side panel by default, these then expand when selected to show all H2 headers.

Due to the limited TOC and sidebar depth, we shouldn’t be afraid of looong pages with many H2 headings to break down the page into logical quadrants.

Emacs rST mode

Emacs’ includes a mode for editing rST files. It is documented on the docutils site

One of the features it includes is readjusting the hierarchy of heading decorations (the underlines for different heading levels). To configure this to use OCIO’s convention, put the following in your .emacs.d/init.el:

(setq rst-preferred-decorations
      '((?= simple 0)
        (?* simple 0)
        (?+ simple 0)
        (?- simple 0)))

OpenColorIO Doxygen Style Guide

This guide introduces a consistent style for documenting OCIO public C++ headers with Doxygen. New code should be documented with the following conventions.

Source Code Documentation Syntax

Doxygen documentation needs only to be applied to the public interface for which we want to generate OCIO API documentation files. Implementation code that does not participate in this should still be enhanced by source code comments as appropriate, but these comments are not required to follow the style outlined here.

Doxygen Tags

The following tags are generally supported:

  • brief: Describes function or class succinctly, ideally in one sentence.

  • param: Describes function parameters.

  • tparam: Describes a template parameter.

  • return: Describes return values.

  • ref: A reference to another method/class.

  • note: Describes a note you want a user to be attentive of.

  • warning: Describes a warning to bring a users attention to.

  • code{<extension>}: The start of a code block. The extension denotes the language e.g. (“.py”, “.cpp”)

  • endcode: The end of a code block.

Additional Doxygen tags may be supported, but will need to be tested by building the Sphinx docs. Not all tags need to be used in every docstring.

Block Comments

Where possible please try to split the tag and names from the descriptive text.

/**
 * \brief A brief description.
 *
 * Detailed description. More detail.
 * \see Some reference
 *
 * \param <name>
 *      Parameter description.
 * \tparam <name>
 *      Template parameter description.
 * \return
 *      Return value description.
 */

Example

/**
 * \brief Returns a compressed version of a string.
 *
 * Compresses an input string using the foobar algorithm.
 *
 * \param
 *      Uncompressed The input string.
 * \return
 *      A compressed version of the input string.
 */
std::string compress(const std::string& uncompressed);

Single Line Comments

Single line comments should be equivalent in scope to the brief in the block comments above. It should be reserved for functions that don’t have parameters, or members that don’t require much description.

/// A brief description.

Example

/// A default constructor
MyClass();

In-Line Comments

In-line comments serve the same purpose as the single line comments, but allows for greater structural flexibility.

///< A brief description.

Example

enum EnumType
{
  int EVal1,     ///< enum description 1.
  int EVal2      ///< enum description 2.
};

Documentation Language

Remember that the docstrings serve both the C++ and Python documentation. Try to use generic language where possible, without referring to C++ or Python constructs exclusively. If you do need to describe additional details for a specific implementation, please refer to which language you are speaking about.