Compare commits

...
27 Commits
Author SHA1 Message Date
Patrick Hodoul 5e414bc9c0 Fix Linux warning
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
2021-12-13 20:57:18 -05:00
3227fa3f76 Adds Metal Support to ociodisplay and enables running GPU tests with Metal backend (#1538)
* * Adds Metal Shading Language (MSL) Generation support

Signed-off-by: Morteza Mostajabodaveh <smostajabodaveh@apple.com>

Co-authored-by: Ingthor Hjalmarsson <ihjalmarsson@apple.com>
Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Fixes warnings triggered due to unused variables.

Signed-off-by: Morteza Mostajabodaveh <smostajabodaveh@apple.com>
Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Fixes compilation error on Mac and Windows:
- vector of const objects causing compiler errors on windows.
- Wrong string was used for Metal language python binding.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Removes class wrapping interface from OpenColorIO interface and move it to implementation
* Adding more tests for metal code path
* Proper generated Metal code indentation
* Fixes a few coding style inconsistencies and unneeded include files

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Remove the unneeded empty line to reset OpenColorIO.h to what it was before the metal change.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * switching from c-like getFunctionParameters function to c++-like one since it is not in the opencolorio interface anymore.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Missing include causing compiler errors on windows

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Fixes and improvements follow up to change that was trying to move metal related code in implementation, and hide them from OCIO interface.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* - remove unused variables.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Adds support for uniform parameters and proper handling of them in metal code.
* Adds two new tests for uniforms and helper functions.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * making declaration parsing more C++-like. Functions like sscanf are problematic when it comes to multiple platform support and may not be safe

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Switching from clf/lut1d_half_domain_raw_half_set.clf  to clf/lut1d_long.clf. Due to decimal number outputting difference between different platforms, some tests were failing.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Moving Metal only functionalities to MetalClassWrappingInterface
* remove unnecessary functions and data types
* code clean up and quality improvement

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Adds support for uniforms that are array
* Removing getTextureKeyword() and getTextureDeclaration() as they are not needed.
* code clean up and quality improvement

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Remove unnecessary changes to GpuShaderUtils_tests.cpp

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Removed unnecessary included files

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Removing unnecessary include

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Apply style improvement suggestions

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * changed from msl_metal to msl_2 so it matches with `GpuLanguageFromString` function.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Move MetalShaderClassWrappingInterface to a separate file and generalise it

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* header files inlcudes clean up

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Still the else path is needed in case we set language from MSL2 to something else.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* [minor] Showing the GpuShaderClassWrapper.h also in the vc15 aftereffect project.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Run ClassWrapper function for all backends. It only produces code in metal shading language code generation case.
operator= for GpuShaderClassWrapper

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* use factory pattern instead of updateClassWrappingInterface

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Replace assignment operator with clone function that is more explicit.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* use Assignment operator instead of setting members in clone member function

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* add include guards.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* make output of MetalShaderClassWrapper::operator= non-const

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Update default branch name (#1532)

Signed-off-by: Michael Dolan <michdolan@gmail.com>

Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>
Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* Adsk Contrib - Default to C++14 and remove OIIO from ocioperf (#1516)

* Adsk Contrib - Default to C++14 and remove OIIO from ocioperf

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Fix cmake breaks

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Fix bit-depths

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Fix Linux build break

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Improve the image generation

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Improve the image generation

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* Add metal rendering support to ociodisplay

Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* Adds support for metal only input texture

Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* Returning correct value for maximum texture width

Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* Add GPU rendering tests for metal renderer
Fixes incorrect shader generation code for arrays in uniform buffer
Adds support for vector comparison in Metal

Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* Fixes failing test_cpu_exec test
Fixes compilation error on Linux, older clang compiler
Makes the app working on x64 Macs

Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* Add support for test that apply color correction multiple times with different setups
replaces asserts with exception
Disables fast math to get more accurate results

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Matching the uniform buffer size elements for array of ints and float to fix two gpu tests

Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* enables -gpuinfo to print shader

Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* Revert "Matching the uniform buffer size elements for array of ints and float to fix two gpu tests"

This reverts commit c1695e20b336c54c618a541cc47311a61399457b.

Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* Enables uniform data binding for metal without touching OCIO interface

Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* set dummy buffers for the vectors that are empty.

Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* Update metal test to reflect latest changes in metal shader generator

Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* Improving coding style
Adds metal gpu unit tests to the one executing

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Updating the test so it reflects latest code changes.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* sets the opengl state even when no valid ocio config is loaded.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Handles metal resources lifecycles correctly. Fixes the crash on transform change.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Applying improvements to code and minor fixes

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Disable testing NaN and Infinity on Apple Silicon that causes test failures and precision errors

Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* make the condition for disabling NaN and INFs more accurate.

Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

* Improving code quality
Fixing possible texture mem leaks

Signed-off-by: Morteza Mostajab <smostajabodaveh@apple.com>

Co-authored-by: Ingthor Hjalmarsson <ihjalmarsson@apple.com>
Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>
Co-authored-by: Michael Dolan <michdolan@gmail.com>
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
2021-12-13 20:57:05 -05:00
ffba80b34c Adds Metal Shading Language (MSL) Generation support (#1520) (#1557)
* * Adds Metal Shading Language (MSL) Generation support

Signed-off-by: Morteza Mostajabodaveh <smostajabodaveh@apple.com>

Co-authored-by: Ingthor Hjalmarsson <ihjalmarsson@apple.com>
Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Fixes warnings triggered due to unused variables.

Signed-off-by: Morteza Mostajabodaveh <smostajabodaveh@apple.com>
Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Fixes compilation error on Mac and Windows:
- vector of const objects causing compiler errors on windows.
- Wrong string was used for Metal language python binding.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Removes class wrapping interface from OpenColorIO interface and move it to implementation
* Adding more tests for metal code path
* Proper generated Metal code indentation
* Fixes a few coding style inconsistencies and unneeded include files

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Remove the unneeded empty line to reset OpenColorIO.h to what it was before the metal change.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * switching from c-like getFunctionParameters function to c++-like one since it is not in the opencolorio interface anymore.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Missing include causing compiler errors on windows

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Fixes and improvements follow up to change that was trying to move metal related code in implementation, and hide them from OCIO interface.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* - remove unused variables.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Adds support for uniform parameters and proper handling of them in metal code.
* Adds two new tests for uniforms and helper functions.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * making declaration parsing more C++-like. Functions like sscanf are problematic when it comes to multiple platform support and may not be safe

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Switching from clf/lut1d_half_domain_raw_half_set.clf  to clf/lut1d_long.clf. Due to decimal number outputting difference between different platforms, some tests were failing.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Moving Metal only functionalities to MetalClassWrappingInterface
* remove unnecessary functions and data types
* code clean up and quality improvement

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Adds support for uniforms that are array
* Removing getTextureKeyword() and getTextureDeclaration() as they are not needed.
* code clean up and quality improvement

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Remove unnecessary changes to GpuShaderUtils_tests.cpp

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Removed unnecessary included files

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Removing unnecessary include

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * Apply style improvement suggestions

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* * changed from msl_metal to msl_2 so it matches with `GpuLanguageFromString` function.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Move MetalShaderClassWrappingInterface to a separate file and generalise it

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* header files inlcudes clean up

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Still the else path is needed in case we set language from MSL2 to something else.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* [minor] Showing the GpuShaderClassWrapper.h also in the vc15 aftereffect project.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Run ClassWrapper function for all backends. It only produces code in metal shading language code generation case.
operator= for GpuShaderClassWrapper

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* use factory pattern instead of updateClassWrappingInterface

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* Replace assignment operator with clone function that is more explicit.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* use Assignment operator instead of setting members in clone member function

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* add include guards.

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

* make output of MetalShaderClassWrapper::operator= non-const

Signed-off-by: Morteza Mostajab <smostajabodaveh@Apple.com>

Co-authored-by: Ingthor Hjalmarsson <ihjalmarsson@apple.com>
Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

Co-authored-by: Morteza Mostajab <92918486+Morteeza@users.noreply.github.com>
Co-authored-by: Ingthor Hjalmarsson <ihjalmarsson@apple.com>
2021-12-13 14:21:11 -05:00
Patrick Hodoulanddoug-walker 0c2aacb6c9 Adsk Contrib - Fix RGB spline curve inversion when the slope is zero (#1539) (#1551)
* Fix RGBCurve inverse when slope=0

Signed-off-by: Doug Walker <Doug.Walker@autodesk.com>

* Add GPU fix and test

Signed-off-by: Doug Walker <Doug.Walker@autodesk.com>

* Tweak var name

Signed-off-by: Doug Walker <Doug.Walker@autodesk.com>

Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

Co-authored-by: doug-walker <43830961+doug-walker@users.noreply.github.com>
2021-12-10 11:40:21 -05:00
Patrick Hodoulandamyspark 6c8cf83375 Implement locale-agnostic number parsing (#1496) (#1548)
This commit adds support for parsing numbers without being influenced by
the current system locale. We implement a from_chars
shim that forwards the call to strto*_l along with a statically
initialized locale constant.

Fixes AcademySoftwareFoundation#297
Fixes AcademySoftwareFoundation#379
Fixes AcademySoftwareFoundation#1322

Co-Authored-By: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

Signed-off-by: amyspark <13498015+amyspark@users.noreply.github.com>

Co-authored-by: amyspark <13498015+amyspark@users.noreply.github.com>
2021-12-09 15:24:01 -05:00
Patrick Hodoul 7a76cceb57 Adsk Contrib - Fix some weaknesses in the search path validation (#1535) (#1545)
* Adsk Contrib - Fix some weaknesses in the search path validation

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Fix the Windows path in the unit test validations

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Fix the Windows path in the unit test validations, part II

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
2021-12-07 16:12:28 -05:00
Rémi Achard b37089aefb Port from main to RB-2.1 - Python 3.10 macOS wheels (#1544)
* Enable mac OS Python 3.10 wheels

Disable Wheel build on OCIO forks

Signed-off-by: Rémi Achard <remiachard@gmail.com>

* Update CI workflow to match main branch

Signed-off-by: Rémi Achard <remiachard@gmail.com>
2021-12-07 14:31:23 -05:00
177a927ff5 Fix add_test calls and change temporary file creation. (#1522) (#1534)
* * Fix add_test in cmake files. This notation allows it to understand that the command portion is a target and to translate it to the proper executable.
* Remove starting backslash if present from temporary filename. A starting backslash mean that it is safe to create it in the current working directory.
* Implement a public TempFile class.
* Change relevant tests to use TempFile class.

Signed-off-by: Patrick Northon <northon_patrick3@yahoo.ca>

* * Revert back changes for TempFile class.
* Add comment on temporary file functions fix.

Signed-off-by: Patrick Northon <northon_patrick3@yahoo.ca>

* Add FIXME comments.

Signed-off-by: Patrick Northon <northon_patrick3@yahoo.ca>

* Add -C flag to ctest commands.

Signed-off-by: Patrick Northon <northon_patrick3@yahoo.ca>

* Add `-C Release` to ctest commands in `analysis_workflow.yml`.

Signed-off-by: Patrick Northon <northon_patrick3@yahoo.ca>

Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>
Co-authored-by: Rémi Achard <remiachard@gmail.com>
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

Co-authored-by: patlefort <northon_patrick3@yahoo.ca>
Co-authored-by: Rémi Achard <remiachard@gmail.com>
2021-11-05 09:22:47 -04:00
Patrick Hodoul a64e4d5d48 Adsk Contrib - Fix the CDL write for CLF file format (#1526) (#1529)
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
2021-11-02 18:01:18 -04:00
Patrick HodoulandMei Chu 198c888ee9 ConfigTest - Virtual display python unit test (#1481) (#1528)
* -ConfigTest: Python unit test updated with additional virtual display tests.

Signed-off-by: Mei Chu <meimchu@gmail.com>

* -ConfigTest: Addressed feedbacks.

Signed-off-by: Mei Chu <meimchu@gmail.com>

* -ConfigTest: Addressing feedbacks on typos.
Signed-off-by: Mei Chu <meimchu@gmail.com>

Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

Co-authored-by: Mei Chu <33743518+meimchu@users.noreply.github.com>
2021-11-02 09:30:04 -04:00
Patrick Hodoulanditsmattkc b252372b7c Fixes Unicode paths on Windows (#1363) (#1527)
* Fixes Unicode paths on Windows

Unlike most other platforms, Windows' Unicode is standardized around
UTF-16, an encoding not compatible with "char *" arrays common in
C/C++. As such, to support Unicode correctly when using Win32 APIs,
strings must be converted to and from UTF-16 and the Unicode
versions of the APIs must be used over the ANSI versions.

This commit introduces the following:

- Utility funcions for converting between UTF-8 and UTF-16LE on all
  platforms:
  - Platform::Utf8ToUtf16
  - Platform::Utf16ToUtf8

- Adds test for these conversion functions to ensure the conversion
  to and from UTF-8 and UTF-16LE is correct.

- Utility wrappers for "std::ifstream" that automatically convert
  to and from UTF-16 so that filenames requiring Unicode encoding
  function correctly:
  - Platform::CreateInputFileStream
  - Platform::OpenInputFileStream

- Moves the file default compute hash function to the Platform
  class (Platform::CreateFileContentHash) and switches to the
  Win32 UTF-16 variant on Windows.

- Adds the "UNICODE" macro before including "Windows.h" which
  ensures all functions called are the Unicode variants instead of
  the default ANSI variants.
  - Implicitly changes functions such as GetEnvironmentVariable and
    SetEnvironmentVariable to their Unicode variants.

- Changes the following environment variable related functions to
  their Win32 Unicode variants on Windows:
  - environ -> _wenviron
  - _putenv_s -> _wputenv_s

- Updates tests using SetEnvironmentVariable to use wide string
  literals since that function has been switched to the Unicode
  variant.

Signed-off-by: itsmattkc <itsmattkc@gmail.com>

* Moved UNICODE and _UNICODE definitions to CMake

Signed-off-by: itsmattkc <34096995+itsmattkc@users.noreply.github.com>

* handle empty strings and use const references

Signed-off-by: itsmattkc <34096995+itsmattkc@users.noreply.github.com>

* only use wenviron when unicode is enabled

Signed-off-by: itsmattkc <itsmattkc@gmail.com>

* add ANSI Win32 version of Getenv

Signed-off-by: itsmattkc <itsmattkc@gmail.com>

* Add CMake option for compiling with Win32 Unicode support

Signed-off-by: itsmattkc <itsmattkc@gmail.com>

* Throw exception if UTF functions are called on non-Windows platforms

Signed-off-by: itsmattkc <itsmattkc@gmail.com>

* Throw OCIO Exception

Signed-off-by: itsmattkc <itsmattkc@gmail.com>

* Don't run UTF-8/16 conversion test on non-Windows

Signed-off-by: itsmattkc <34096995+itsmattkc@users.noreply.github.com>

* Fix CMake error

Signed-off-by: itsmattkc <34096995+itsmattkc@users.noreply.github.com>

* minor CMake adjustment

Signed-off-by: itsmattkc <itsmattkc@gmail.com>

* Clarified CMake option for Win32 unicode

Signed-off-by: itsmattkc <34096995+itsmattkc@users.noreply.github.com>

* minor improvements

Signed-off-by: itsmattkc <34096995+itsmattkc@users.noreply.github.com>

* fix macro in cpu test cmake

Signed-off-by: itsmattkc <34096995+itsmattkc@users.noreply.github.com>

Co-authored-by: itsmattkc <34096995+itsmattkc@users.noreply.github.com>
2021-10-31 20:20:47 -04:00
Patrick Hodoul 17e52e38c6 Adsk Contrib - Improve the OSL unit test framework (#1514) (#1524)
* Adsk Contrib - Improve the OSL unit test framework

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Fix a Linux build break

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Fix a 'git rebase' break

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Some improvements

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Workaround to sucesfully link with OSL

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Found the right fix

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Add more tests for Grading ops

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Improve OSL library find

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Fix with OpenImageIO version requires C++14

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Another OSL cmake improvement

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
2021-10-27 23:06:09 -04:00
Patrick HodoulandGuillaume Papin 7360206858 CMake: remove duplicate find_package(pybind11 ...) (#1521) (#1523)
This duplicate seems to come from the PR #1371.
This PR spanned April 15 - August 24 (2021).

Meanwhile, PR #1410 (June 13 - June 21),
changed the CMake logic around `find_package(pybind11 ...)`.

It looks like former PR mishandled the merge of the latter.

Signed-off-by: Guillaume Papin <guillaume.papin@epitech.eu>

Co-authored-by: Guillaume Papin <guillaume.papin@epitech.eu>
2021-10-26 18:50:59 -04:00
934b80829b Add Python GPU renderer implementation example (#1493) (#1518)
* Add Python GPU renderer implementation example

Signed-off-by: Michael Dolan <michdolan@gmail.com>

* Move to apps with README

Signed-off-by: Michael Dolan <michdolan@gmail.com>

Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>
Co-authored-by: Rémi Achard <remiachard@gmail.com>

Co-authored-by: Michael Dolan <michdolan@gmail.com>
Co-authored-by: Rémi Achard <remiachard@gmail.com>
2021-10-21 13:45:04 -04:00
Patrick HodoulandRémi Achard 36845c3f32 Fix install paths regressions (#1502) (#1510)
* Fix install directory variable for python bindings

Signed-off-by: Rémi Achard <remiachard@gmail.com>

* Remove hardcoded lib prefix in RPATH handling

Signed-off-by: Rémi Achard <remiachard@gmail.com>

Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>

Co-authored-by: Rémi Achard <remiachard@gmail.com>
2021-10-19 14:01:47 -04:00
Patrick HodoulandHenry Schreiner 2d318af010 chore: update to new cibuildwheel location (#1513) (#1517)
Signed-off-by: Henry Schreiner <henryschreineriii@gmail.com>

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
2021-10-18 11:18:47 -04:00
Patrick HodoulandBo Zhou 445c45b016 Write converted image with output colorspace (#1420) (#1500) (#1511)
* Write converted image with output colorspace (#1420)

Signed-off-by: Bo Zhou <Bo.Schwarzstein@gmail.com>

* Check if outputcolorspace is null and set it as oiio:ColorSpace (#1460)

Signed-off-by: Bo Zhou <Bo.Schwarzstein@gmail.com>

* Call getDisplayViewColorSpaceName to get output colorspace for view mode. #1420

Signed-off-by: Bo Zhou <Bo.Schwarzstein@gmail.com>

Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>

Co-authored-by: Bo Zhou <bo.schwarzstein@gmail.com>
2021-10-07 08:33:18 -04:00
Rémi AchardandPatrick Hodoul d950ab4bf7 Remove Python wheel workflow running on every pull request (#1503) (#1512)
Signed-off-by: Rémi Achard <remiachard@gmail.com>

Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>

Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>
2021-10-06 16:06:55 -04:00
Patrick Hodoulandamyspark d331992d93 Add support for OpenGL ES as a shading language (#1497) (#1504)
* Add support for OpenGL ES as a shading language

This commit adds two new entries to `GpuLanguage`,
`GPU_LANGUAGE_GLSL_ES_1_0` and `GPU_LANGUAGE_GLSL_ES_3_0`.

The only meaningful differences w.r.t. stock OpenGL are:

- the 1D texture optimization isn't applied to ES, as they are not
  supported at all;

- the texture<N>D() calls are replaced in GLSL ES 3 by a call to
  texture().

Fixes #1486

Signed-off-by: L. E. Segovia <13498015+amyspark@users.noreply.github.com>

* GLSL ES: remove ABI break

Signed-off-by: L. E. Segovia <13498015+amyspark@users.noreply.github.com>

* OpenGLBuilder: use switch to check GLSL version

Signed-off-by: L. E. Segovia <13498015+amyspark@users.noreply.github.com>
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

Co-authored-by: amyspark <13498015+amyspark@users.noreply.github.com>
2021-10-06 08:25:47 -04:00
Patrick Hodoul 9c5a324184 Adsk Contrib - Fix the analysis workflow (#1492) (#1506)
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
2021-10-05 18:27:23 -04:00
Patrick Hodoul 2716337500 Adsk contrib - Various improvements (#1489) (#1505)
* Adsk Contrib - Small oiiohelper improvement

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Try to fix some memory issues report by valgrind

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Improve ctest support and add another check for OpenImageIO

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Fix Windows build failure

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Fix binary names on Windows

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Improve code around FixedFunction Ops

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Improve ctest support

Signed-off-by: hodoulp <Patrick.Hodoul@autodesk.com>

* Fix cmake

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
2021-10-05 13:49:45 -04:00
Patrick Hodoulandamyspark 30ac2904e3 Add support for MinGW (#1485) (#1501)
In these cases the build system doesn't add a suffix to yaml-cpp.

Signed-off-by: amyspark <13498015+amyspark@users.noreply.github.com>

Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>

Co-authored-by: amyspark <13498015+amyspark@users.noreply.github.com>
2021-10-04 14:27:48 -04:00
Patrick Hodoulandamyspark ce3042cd10 FindExpat: allow usage of expat 2.2.9 (#1483) (#1499)
- alias expat::expat to expat::libexpat if the former is missing
- patch INTERFACE_INCLUDE_DIRECTORIES if the property is missing

Fixes #1482.

Signed-off-by: amyspark <13498015+amyspark@users.noreply.github.com>

Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>

Co-authored-by: amyspark <13498015+amyspark@users.noreply.github.com>
2021-10-04 09:30:41 -04:00
Patrick Hodoul 15ffc9a414 Adsk Contrib - Remove the useless cmake target on oiiotool (#1477) (#1494)
* Adsk Contrib - REmove the useless cmake target on oiiotool

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Improve the OIIO Util library support

Signed-off-by: hodoulp <Patrick.Hodoul@autodesk.com>
2021-09-25 09:47:09 -04:00
Patrick HodoulandRémi Achard 7ec43b7d93 Remove OpenColorIOHeaders target and hardcoded install paths (#1471) (#1490)
* Remove OpenColorIOHeaders target

Signed-off-by: Rémi Achard <remiachard@gmail.com>

* Avoid hardcoding install paths

Signed-off-by: Rémi Achard <remiachard@gmail.com>

* Update remaining hardcoded install paths

Signed-off-by: Rémi Achard <remiachard@gmail.com>

* Replace LIB_SUFFIX by CMAKE_INSTALL_LIBDIR

Signed-off-by: Rémi Achard <remiachard@gmail.com>

Co-authored-by: Patrick Hodoul <patrick.hodoul@autodesk.com>

Co-authored-by: Rémi Achard <remiachard@gmail.com>
2021-09-23 14:06:28 -04:00
Patrick Hodoul 83d3412ff2 Adsk Contrib - Better manage Imath dependency (#1478) (#1488)
* Adsk Contrib - Better manage Imath dependency

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>

* Add the OpenImageIO_Util dependency to OSL unit test framework

Signed-off-by: hodoulp <Patrick.Hodoul@autodesk.com>

* Fix oiio typo

Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
2021-09-21 16:17:14 -04:00
Patrick Hodoul 156d4ffda0 Adsk Contrib - Change RB-2.1 branch to the version '2.1.1dev' (#1479)
Signed-off-by: Patrick Hodoul <Patrick.Hodoul@autodesk.com>
2021-09-16 08:45:42 -04:00
132 changed files with 9998 additions and 1401 deletions
+4 -4
View File
@@ -122,7 +122,7 @@ jobs:
-- -j$(nproc)
working-directory: _build
- name: Test
run: ctest -V
run: ctest -V -C Release
working-directory: _build
# ---------------------------------------------------------------------------
@@ -130,7 +130,7 @@ jobs:
# ---------------------------------------------------------------------------
linux_sonarcloud:
name: 'Linux CentOS 7 VFX CY2020 SonarCloud <GCC 6.3.1>'
name: 'Linux CentOS 7 VFX CY2022 SonarCloud <GCC 9.3.1>'
# Don't run on OCIO forks
if: github.repository == 'AcademySoftwareFoundation/OpenColorIO'
# GH-hosted VM. The build runs in CentOS 7 'container' defined below.
@@ -160,7 +160,7 @@ jobs:
cmake ../. \
-DCMAKE_INSTALL_PREFIX=../_install \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_STANDARD=11 \
-DCMAKE_CXX_STANDARD=14 \
-DCMAKE_CXX_FLAGS="-g -O0 -fprofile-arcs -ftest-coverage" \
-DCMAKE_CXX_OUTPUT_EXTENSION_REPLACE=ON \
-DCMAKE_EXE_LINKER_FLAGS="-lgcov" \
@@ -174,7 +174,7 @@ jobs:
run: build-wrapper-linux-x86-64 --out-dir bw_output make clean all
working-directory: _build
- name: Test
run: ctest -V
run: ctest -V -C Release
working-directory: _build
- name: Generate code coverage report
run: share/ci/scripts/linux/run_gcov.sh
+46 -20
View File
@@ -47,6 +47,10 @@ jobs:
sse=${{ matrix.use-sse }},
cxx=${{ matrix.cxx-standard }},
docs=${{ matrix.build-docs }}>'
# Avoid duplicated checks when a pull_request is opened from a local branch.
if: |
github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name != github.repository
# GH-hosted VM. The build runs in CentOS 7 'container' defined below.
runs-on: ubuntu-latest
container:
@@ -55,13 +59,13 @@ jobs:
image: aswf/ci-ocio:${{ matrix.vfx-cy }}
strategy:
matrix:
build: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
build: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
include:
# -------------------------------------------------------------------
# VFX CY2022 (Python 3.9)
# -------------------------------------------------------------------
# Clang, Debug, OpenFX
- build: 12
- build: 13
build-type: Debug
build-shared: 'ON'
build-docs: 'OFF'
@@ -74,7 +78,7 @@ jobs:
compiler-desc: Clang 9
vfx-cy: 2022
# GCC, no SSE, OpenFX
- build: 11
- build: 12
build-type: Release
build-shared: 'ON'
build-docs: 'OFF'
@@ -86,15 +90,28 @@ jobs:
cc-compiler: gcc
compiler-desc: GCC 9.3.1
vfx-cy: 2022
# GCC, static, docs
- build: 10
# C++14, GCC, static, docs
- build: 11
build-type: Release
build-shared: 'OFF'
build-docs: 'ON'
build-openfx: 'OFF'
use-sse: 'ON'
use-openexr-half: 'OFF'
cxx-standard: 17
cxx-standard: 14
cxx-compiler: g++
cc-compiler: gcc
compiler-desc: GCC 9.3.1
vfx-cy: 2022
# C++11, GCC, static
- build: 10
build-type: Release
build-shared: 'OFF'
build-docs: 'OFF'
build-openfx: 'OFF'
use-sse: 'ON'
use-openexr-half: 'OFF'
cxx-standard: 11
cxx-compiler: g++
cc-compiler: gcc
compiler-desc: GCC 9.3.1
@@ -115,7 +132,7 @@ jobs:
cc-compiler: clang
compiler-desc: Clang 9
vfx-cy: 2021
# Clang, static, no SSE, OpenFX
# C++14, Clang, static, no SSE, OpenFX
- build: 8
build-type: Release
build-shared: 'OFF'
@@ -123,12 +140,12 @@ jobs:
build-openfx: 'ON'
use-sse: 'OFF'
use-openexr-half: 'ON'
cxx-standard: 17
cxx-standard: 14
cxx-compiler: clang++
cc-compiler: clang
compiler-desc: Clang 9
vfx-cy: 2021
# GCC, Debug
# C++11, GCC, Debug
- build: 7
build-type: Debug
build-shared: 'ON'
@@ -136,7 +153,7 @@ jobs:
build-openfx: 'OFF'
use-sse: 'ON'
use-openexr-half: 'ON'
cxx-standard: 17
cxx-standard: 11
cxx-compiler: g++
cc-compiler: gcc
compiler-desc: GCC 9.3.1
@@ -144,7 +161,7 @@ jobs:
# -------------------------------------------------------------------
# VFX CY2020 (Python 3.7)
# -------------------------------------------------------------------
# Clang, OpenFX
# C++14, Clang, OpenFX
- build: 6
build-type: Release
build-shared: 'ON'
@@ -157,7 +174,7 @@ jobs:
cc-compiler: clang
compiler-desc: Clang 7
vfx-cy: 2020
# GCC, static, Debug, OpenFX
# C++14, GCC, static, Debug, OpenFX
- build: 5
build-type: Debug
build-shared: 'OFF'
@@ -170,7 +187,7 @@ jobs:
cc-compiler: gcc
compiler-desc: GCC 6.3.1
vfx-cy: 2020
# GCC, no SSE, docs
# C++11, GCC, no SSE, docs
- build: 4
build-type: Release
build-shared: 'ON'
@@ -178,7 +195,7 @@ jobs:
build-openfx: 'OFF'
use-sse: 'ON'
use-openexr-half: 'ON'
cxx-standard: 14
cxx-standard: 11
cxx-compiler: g++
cc-compiler: gcc
compiler-desc: GCC 6.3.1
@@ -186,7 +203,7 @@ jobs:
# -------------------------------------------------------------------
# VFX CY2019 (Python 2.7)
# -------------------------------------------------------------------
# Clang, static
# C++11, Clang, static
- build: 3
build-type: Release
build-shared: 'OFF'
@@ -200,7 +217,7 @@ jobs:
cc-compiler: clang
compiler-desc: Clang 7
vfx-cy: 2019
# Clang, Debug, no SSE
# C++11, Clang, Debug, no SSE
- build: 2
build-type: Debug
build-shared: 'ON'
@@ -214,7 +231,7 @@ jobs:
cc-compiler: clang
compiler-desc: Clang 7
vfx-cy: 2019
# GCC, OpenFX
# C++11, GCC, OpenFX
- build: 1
build-type: Release
build-shared: 'ON'
@@ -267,7 +284,7 @@ jobs:
-- -j$(nproc)
working-directory: _build
- name: Test
run: ctest -V
run: ctest -V -C ${{ matrix.build-type }}
working-directory: _build
- name: Test CMake Consumer
if: matrix.build-shared == 'ON'
@@ -293,6 +310,10 @@ jobs:
cxx=${{ matrix.cxx-standard }},
python=${{ matrix.python-version }},
docs=${{ matrix.build-docs }}>'
# Avoid duplicated checks when a pull_request is opened from a local branch.
if: |
github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name != github.repository
runs-on: macos-10.15
strategy:
matrix:
@@ -399,7 +420,7 @@ jobs:
-- -j$(sysctl -n hw.ncpu)
working-directory: _build
- name: Test
run: ctest -V
run: ctest -V -C ${{ matrix.build-type }}
working-directory: _build
- name: Test CMake Consumer
if: matrix.build-shared == 'ON'
@@ -427,6 +448,10 @@ jobs:
cxx=${{ matrix.cxx-standard }},
python=${{ matrix.python-version }},
docs=${{ matrix.build-docs }}>'
# Avoid duplicated checks when a pull_request is opened from a local branch.
if: |
github.event_name == 'push' ||
github.event.pull_request.head.repo.full_name != github.repository
runs-on: windows-2019
strategy:
matrix:
@@ -506,6 +531,7 @@ jobs:
if: matrix.build-docs == 'ON'
- name: Install tests env
run: share/ci/scripts/windows/install_tests_env.sh
shell: bash
- name: Create build directories
run: |
mkdir _install
@@ -537,7 +563,7 @@ jobs:
shell: bash
working-directory: _build
- name: Test
run: ctest -V
run: ctest -V -C ${{ matrix.build-type }}
shell: bash
working-directory: _build
- name: Test CMake Consumer
+68 -37
View File
@@ -6,15 +6,11 @@ name: Wheel
on:
push:
# Versioned branches and tags are ignored for OCIO <= 1.x.x
branches-ignore:
- RB-0.*
- RB-1.*
- gh-pages
tags-ignore:
- v0.*
- v1.*
# Workflow run on tags for v2 only.
tags:
- v2.*
pull_request:
# Workflow run on pull_request only when related files change.
branches-ignore:
- RB-0.*
- RB-1.*
@@ -22,6 +18,12 @@ on:
tags-ignore:
- v0.*
- v1.*
paths:
- .github/workflows/wheel_workflow.yml
- pyproject.toml
schedule:
# Nightly build
- cron: "0 0 * * *"
jobs:
# Linux jobs run in Docker containers (manylinux), so the latest OS version
@@ -29,18 +31,8 @@ jobs:
# environment versions to mitigate issues from OS updates, and will require
# maintenance as OS versions are retired.
#
# Notes:
#
# Documentation fails to build on manylinux2010, maybe too old
# doxygen ? First fail in PyColorSpaceSet for documentation
# referencing PyOpenColorIO (eg. __sub__). Consequence is we don't
# support python 2.7, alternatively build without docstrings, or
# fix the doxygen issue.
#
# When installing doc environment, Python package are not used as the wheel
# is built in it's own isolated environment, hence package are listed again
# in pyproject.toml.
#
# Due to documentation build failing on manylinux2010 (maybe too old doxygen
# version), we build on manylinux2014 image, this requires pip >= 19.3.
# ---------------------------------------------------------------------------
# Linux
@@ -49,6 +41,10 @@ jobs:
linux:
name: Build wheels on Linux
runs-on: ubuntu-latest
# Don't run on OCIO forks
if: |
github.event_name != 'schedule' ||
github.repository == 'AcademySoftwareFoundation/OpenColorIO'
strategy:
matrix:
include:
@@ -67,6 +63,9 @@ jobs:
- build: CPython 3.9 32 bits
python: cp39-*
arch: i686
- build: CPython 3.10 32 bits
python: cp310-*
arch: i686
# -------------------------------------------------------------------
# CPython 64 bits
# -------------------------------------------------------------------
@@ -82,6 +81,27 @@ jobs:
- build: CPython 3.9 64 bits
python: cp39-*
arch: x86_64
- build: CPython 3.10 64 bits
python: cp310-*
arch: x86_64
# -------------------------------------------------------------------
# CPython ARM 64 bits
# -------------------------------------------------------------------
- build: CPython 3.6 ARM 64 bits
python: cp36-*
arch: aarch64
- build: CPython 3.7 ARM 64 bits
python: cp37-*
arch: aarch64
- build: CPython 3.8 ARM 64 bits
python: cp38-*
arch: aarch64
- build: CPython 3.9 ARM 64 bits
python: cp39-*
arch: aarch64
- build: CPython 3.10 ARM 64 bits
python: cp310-*
arch: aarch64
steps:
- uses: actions/checkout@v2
@@ -91,17 +111,16 @@ jobs:
with:
python-version: '3.8'
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: Build wheels
uses: joerick/cibuildwheel@v1.12.0
uses: pypa/cibuildwheel@v2.1.2
env:
CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
CIBW_MANYLINUX_I686_IMAGE: manylinux2014
CIBW_BUILD_VERBOSITY: 1
CIBW_BUILD: ${{ matrix.python }}
CIBW_ARCHS: ${{ matrix.arch }}
CIBW_BEFORE_BUILD: share/ci/scripts/linux/yum/install_docs_env.sh
CIBW_TEST_REQUIRES: numpy
CIBW_TEST_COMMAND: python -m PyOpenColorIOTests.OpenColorIOTestSuite
- uses: actions/upload-artifact@v2
with:
@@ -114,6 +133,10 @@ jobs:
macos:
name: Build wheels on macOS
runs-on: macos-10.15
# Don't run on OCIO forks
if: |
github.event_name != 'schedule' ||
github.repository == 'AcademySoftwareFoundation/OpenColorIO'
strategy:
matrix:
include:
@@ -132,6 +155,9 @@ jobs:
- build: CPython 3.9 64 bits
python: cp39-*
arch: x86_64
- build: CPython 3.10 64 bits
python: cp310-*
arch: x86_64
# -------------------------------------------------------------------
# CPython ARM 64 bits
# -------------------------------------------------------------------
@@ -141,6 +167,9 @@ jobs:
- build: CPython 3.9 ARM 64 bits
python: cp39-*
arch: arm64
- build: CPython 3.10 ARM 64 bits
python: cp310-*
arch: arm64
steps:
- uses: actions/checkout@v2
@@ -151,14 +180,10 @@ jobs:
python-version: '3.8'
- name: Build wheels
uses: joerick/cibuildwheel@v1.12.0
uses: pypa/cibuildwheel@v2.1.2
env:
CIBW_BUILD_VERBOSITY: 1
CIBW_BUILD: ${{ matrix.python }}
CIBW_ARCHS: ${{ matrix.arch }}
CIBW_BEFORE_BUILD: share/ci/scripts/macos/install_docs_env.sh
CIBW_TEST_REQUIRES: numpy
CIBW_TEST_COMMAND: python -m PyOpenColorIOTests.OpenColorIOTestSuite
- uses: actions/upload-artifact@v2
with:
@@ -171,6 +196,10 @@ jobs:
windows:
name: Build wheels on Windows
runs-on: windows-2019
# Don't run on OCIO forks
if: |
github.event_name != 'schedule' ||
github.repository == 'AcademySoftwareFoundation/OpenColorIO'
strategy:
matrix:
include:
@@ -189,6 +218,9 @@ jobs:
- build: CPython 3.9 32 bits
python: cp39-*
arch: x86
- build: CPython 3.10 32 bits
python: cp310-*
arch: x86
# -------------------------------------------------------------------
# CPython 64 bits
# -------------------------------------------------------------------
@@ -204,6 +236,9 @@ jobs:
- build: CPython 3.9 64 bits
python: cp39-*
arch: AMD64
- build: CPython 3.10 64 bits
python: cp310-*
arch: AMD64
steps:
- uses: actions/checkout@v2
@@ -214,14 +249,10 @@ jobs:
python-version: '3.8'
- name: Build wheels
uses: joerick/cibuildwheel@v1.12.0
uses: pypa/cibuildwheel@v2.1.2
env:
CIBW_BUILD_VERBOSITY: 1
CIBW_BUILD: ${{ matrix.python }}
CIBW_ARCHS: ${{ matrix.arch }}
CIBW_BEFORE_BUILD: bash -c share/ci/scripts/windows/install_docs_env.sh
CIBW_TEST_REQUIRES: numpy
CIBW_TEST_COMMAND: python -m PyOpenColorIOTests.OpenColorIOTestSuite
- uses: actions/upload-artifact@v2
with:
+18 -3
View File
@@ -28,17 +28,30 @@ endif()
# Project definition.
project(OpenColorIO
VERSION 2.1.0
VERSION 2.1.1
DESCRIPTION "OpenColorIO (OCIO) is a complete color management solution"
HOMEPAGE_URL https://github.com/AcademySoftwareFoundation/OpenColorIO
LANGUAGES CXX C)
# "dev", "beta1", rc1", etc or "" for an official release.
set(OpenColorIO_VERSION_RELEASE_TYPE "")
set(OpenColorIO_VERSION_RELEASE_TYPE "dev")
###############################################################################
# ctest
# To correctly generate the DartConfiguration.tcl, include the CTest CMake file.
# By doing so 'ctest -F memcheck' works.
include (CTest)
enable_testing()
###############################################################################
# Provides install directory variables as defined by the GNU Coding Standards.
include(GNUInstallDirs)
###############################################################################
# Forbid in-source build.
@@ -126,6 +139,8 @@ option(OCIO_BUILD_JAVA "Specify whether to build java bindings" OFF)
option(OCIO_WARNING_AS_ERROR "Set build error level for CI testing" OFF)
option(OCIO_USE_WINDOWS_UNICODE "On Windows only, compile with Unicode support" WIN32)
###############################################################################
# Optimization / internal linking preferences
@@ -259,7 +274,6 @@ if(OCIO_BUILD_DOCS)
endif()
add_subdirectory(tests)
add_subdirectory(src)
add_subdirectory(include)
add_subdirectory(ext)
@@ -315,3 +329,4 @@ install(
FILES "${OCIO_PROJECT_CONFIG}" "${OCIO_VERSION_CONFIG}"
DESTINATION "${OCIO_CONFIG_INSTALL_DIR}"
)
+2 -2
View File
@@ -61,8 +61,8 @@ else:
description = "@CMAKE_PROJECT_DESCRIPTION@"
version = "@CMAKE_PROJECT_VERSION@"
version_major = "@OpenColorIO_VERSION_MAJOR@"
version_minor = "@OpenColorIO_VERSION_MAJOR@"
version_patch = "@OpenColorIO_VERSION_MAJOR@"
version_minor = "@OpenColorIO_VERSION_MINOR@"
version_patch = "@OpenColorIO_VERSION_PATCH@"
ocio_namespace = "@OCIO_NAMESPACE@"
author = "Contributors to the {} Project".format(project)
-4
View File
@@ -1,4 +0,0 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright Contributors to the OpenColorIO Project.
add_subdirectory(OpenColorIO)
-32
View File
@@ -1,32 +0,0 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright Contributors to the OpenColorIO Project.
configure_file("OpenColorABI.h.in" "${CMAKE_CURRENT_BINARY_DIR}/OpenColorABI.h" @ONLY)
add_library(OpenColorIOHeaders INTERFACE)
set(BUILD_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}/..
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}/OpenColorIO
)
target_include_directories(OpenColorIOHeaders
INTERFACE
"$<BUILD_INTERFACE:${BUILD_INCLUDES}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
add_dependencies(OpenColorIOHeaders "${CMAKE_CURRENT_BINARY_DIR}/OpenColorABI.h")
# public interface
file(GLOB_RECURSE core_export_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
list(APPEND core_export_headers ${CMAKE_CURRENT_BINARY_DIR}/OpenColorABI.h)
install(FILES ${core_export_headers}
DESTINATION include/OpenColorIO)
install(TARGETS OpenColorIOHeaders
EXPORT ${PROJECT_NAME}_EXPORTED_TARGETS
)
+5 -2
View File
@@ -409,7 +409,7 @@ enum BitDepth
BIT_DEPTH_UINT12,
BIT_DEPTH_UINT14,
BIT_DEPTH_UINT16,
BIT_DEPTH_UINT32,
BIT_DEPTH_UINT32, ///< Here for historical reason but that's not supported.
BIT_DEPTH_F16,
BIT_DEPTH_F32
};
@@ -446,7 +446,10 @@ enum GpuLanguage
GPU_LANGUAGE_GLSL_1_3, ///< OpenGL Shading Language
GPU_LANGUAGE_GLSL_4_0, ///< OpenGL Shading Language
GPU_LANGUAGE_HLSL_DX11, ///< DirectX Shading Language
LANGUAGE_OSL_1 ///< Open Shading Language
LANGUAGE_OSL_1, ///< Open Shading Language
GPU_LANGUAGE_GLSL_ES_1_0, ///< OpenGL ES Shading Language
GPU_LANGUAGE_GLSL_ES_3_0, ///< OpenGL ES Shading Language
GPU_LANGUAGE_MSL_2_0 ///< Metal Shading Language
};
enum EnvironmentMode
+19
View File
@@ -18,3 +18,22 @@ requires = [
"breathe"
]
build-backend = "setuptools.build_meta"
[tool.cibuildwheel]
build-verbosity = "1"
test-command = "python -m PyOpenColorIOTests.OpenColorIOTestSuite"
test-requires = ["numpy"]
manylinux-x86_64-image = "manylinux2014"
manylinux-i686-image = "manylinux2014"
manylinux-aarch64-image = "manylinux2014"
[tool.cibuildwheel.linux]
before-build = "share/ci/scripts/linux/yum/install_docs_env.sh"
[tool.cibuildwheel.macos]
before-build = "share/ci/scripts/macos/install_docs_env.sh"
[tool.cibuildwheel.windows]
before-build = "bash -c share/ci/scripts/windows/install_docs_env.sh"
-13
View File
@@ -74,19 +74,6 @@ if(OCIO_BUILD_OPENFX)
find_package(openfx 1.4 REQUIRED)
endif()
if(OCIO_BUILD_PYTHON)
# NOTE: Depending of the compiler version pybind11 2.4.3 does not compile
# with C++17 so, if you change the pybind11 version update the code to
# compile pybind11 and dependencies with C++17 or higher i.e. remove the
# cap of C++ version in FindPybind11.cmake and
# src/bindings/python/CMakeLists.txt.
# pybind11
# https://github.com/pybind/pybind11
find_package(pybind11 2.6.1 REQUIRED)
endif()
if (OCIO_PYTHON_VERSION AND NOT OCIO_BUILD_PYTHON)
message (WARNING "OCIO_PYTHON_VERSION=${OCIO_PYTHON_VERSION} but OCIO_BUILD_PYTHON is off.")
endif ()
+4
View File
@@ -203,6 +203,10 @@ if(NOT Imath_FOUND)
)
add_dependencies(Imath::Imath imath_install)
# Some Imath versions define a second target.
add_library(Imath::ImathConfig ALIAS Imath::Imath)
message(STATUS "Installing Imath: ${Imath_LIBRARY} (version \"${Imath_VERSION}\")")
endif()
endif()
+17 -9
View File
@@ -21,7 +21,6 @@
# OPENIMAGEIO_VERSION_MINOR Version minor number
# OPENIMAGEIO_VERSION_PATCH Version minor patch
# OPENIMAGEIO_VERSION_TWEAK Version minor tweak
# OIIOTOOL_BIN Path to oiiotool executable
#
# Imported targets:
# OpenImageIO::OpenImageIO The libOpenImageIO library.
@@ -59,12 +58,13 @@ find_library ( OPENIMAGEIO_LIBRARY
NAMES OpenImageIO${OIIO_LIBNAME_SUFFIX}
HINTS ${OPENIMAGEIO_ROOT_DIR}
PATH_SUFFIXES lib64 lib )
find_library ( OPENIMAGEIO_UTIL_LIBRARY
NAMES OpenImageIO_Util${OIIO_LIBNAME_SUFFIX}
HINTS ${OPENIMAGEIO_ROOT_DIR}
PATH_SUFFIXES lib64 lib )
find_path ( OPENIMAGEIO_INCLUDE_DIR
NAMES OpenImageIO/imageio.h
HINTS ${OPENIMAGEIO_ROOT_DIR} )
find_program ( OIIOTOOL_BIN
NAMES oiiotool
HINTS ${OPENIMAGEIO_ROOT_DIR} )
# Try to figure out version number
set (OIIO_VERSION_HEADER "${OPENIMAGEIO_INCLUDE_DIR}/OpenImageIO/oiioversion.h")
@@ -102,7 +102,6 @@ if (OpenImageIO_FOUND)
message ( STATUS "OpenImageIO includes = ${OPENIMAGEIO_INCLUDE_DIR}" )
message ( STATUS "OpenImageIO libraries = ${OPENIMAGEIO_LIBRARIES}" )
message ( STATUS "OpenImageIO library_dirs = ${OPENIMAGEIO_LIBRARY_DIRS}" )
message ( STATUS "OpenImageIO oiiotool = ${OIIOTOOL_BIN}" )
endif ()
if (NOT TARGET OpenImageIO::OpenImageIO)
@@ -114,10 +113,19 @@ if (OpenImageIO_FOUND)
IMPORTED_LOCATION "${OPENIMAGEIO_LIBRARIES}")
endif ()
if (NOT TARGET OpenImageIO::oiiotool AND EXISTS "${OIIOTOOL_BIN}")
add_executable(OpenImageIO::oiiotool IMPORTED)
set_target_properties(OpenImageIO::oiiotool PROPERTIES
IMPORTED_LOCATION "${OIIOTOOL_BIN}")
# Starting with OIIO v2.3, some utility classes are now only declared in OpenImageIO_Util
# (and not in both libraries like in older versions).
if (${OPENIMAGEIO_VERSION} VERSION_GREATER_EQUAL "2.3" AND NOT TARGET OpenImageIO::OpenImageIO_Util)
add_library(OpenImageIO::OpenImageIO_Util UNKNOWN IMPORTED)
set_target_properties(OpenImageIO::OpenImageIO_Util PROPERTIES
IMPORTED_LOCATION "${OPENIMAGEIO_UTIL_LIBRARY}")
target_link_libraries(OpenImageIO::OpenImageIO INTERFACE OpenImageIO::OpenImageIO_Util)
endif ()
# Starting with OIIO v2.3, OIIO needs to compile at least in C++14.
if (${OPENIMAGEIO_VERSION} VERSION_GREATER_EQUAL "2.3" AND ${CMAKE_CXX_STANDARD} LESS_EQUAL 11)
set(OpenImageIO_FOUND OFF)
message(WARNING "Need C++14 or higher to compile with OpenImageIO ${OPENIMAGEIO_VERSION}.")
endif ()
endif ()
@@ -7,22 +7,59 @@
# variable to tell CMake where to find it.
#
# TODO: OSL: Use "find_package(OSL 1.11 CONFIG)" directly instead of this file!
if(NOT TARGET osl::osl)
add_library(osl::osl UNKNOWN IMPORTED GLOBAL)
add_library(osl::osl INTERFACE IMPORTED GLOBAL)
set(OSL_FOUND OFF)
endif()
###############################################################################
### Try to find package ###
if(DEFINED OSL_ROOT)
if(NOT DEFINED OSL_ROOT)
find_package(OSL ${OpenShadingLanguage_FIND_VERSION} CONFIG)
set(OpenShadingLanguage_VERSION ${OSL_VERSION})
# TODO: No variable to have the share directory?
set(OSL_SHADERS_INCLUDE_DIR ${OSL_INCLUDE_DIR}/../share)
# Variable used by the OSL unit tests.
set(OSL_SHADERS_DIR ${OSL_SHADERS_INCLUDE_DIR}/OSL/shaders)
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (OpenShadingLanguage
FOUND_VAR OpenShadingLanguage_FOUND
REQUIRED_VARS OSL_INCLUDE_DIR OSL_LIB_DIR OpenShadingLanguage_VERSION
VERSION_VAR OpenShadingLanguage_VERSION
)
set(OSL_FOUND ${OpenShadingLanguage_FOUND})
else()
set(OSL_INCLUDE_DIR ${OSL_ROOT}/include)
if(EXISTS "${OSL_INCLUDE_DIR}/OSL/oslversion.h")
set(OSL_VERSION_HEADER "${OSL_INCLUDE_DIR}/OSL/oslversion.h")
if(EXISTS "${OSL_VERSION_HEADER}")
# Try to figure out version number
file (STRINGS "${OSL_VERSION_HEADER}" TMP REGEX "^#define OSL_LIBRARY_VERSION_MAJOR .*$")
string (REGEX MATCHALL "[0-9]+" OSL_VERSION_MAJOR ${TMP})
file (STRINGS "${OSL_VERSION_HEADER}" TMP REGEX "^#define OSL_LIBRARY_VERSION_MINOR .*$")
string (REGEX MATCHALL "[0-9]+" OSL_VERSION_MINOR ${TMP})
file (STRINGS "${OSL_VERSION_HEADER}" TMP REGEX "^#define OSL_LIBRARY_VERSION_PATCH .*$")
string (REGEX MATCHALL "[0-9]+" OSL_VERSION_PATCH ${TMP})
file (STRINGS "${OSL_VERSION_HEADER}" TMP REGEX "^#define OSL_LIBRARY_VERSION_TWEAK .*$")
if (TMP)
string (REGEX MATCHALL "[0-9]+" OSL_VERSION_TWEAK ${TMP})
else ()
set (OSL_VERSION_TWEAK 0)
endif ()
set (OpenShadingLanguage_VERSION "${OSL_VERSION_MAJOR}.${OSL_VERSION_MINOR}.${OSL_VERSION_PATCH}.${OSL_VERSION_TWEAK}")
# Find the oslcomp library.
find_library(oslcomp_LIBRARY
@@ -34,6 +71,11 @@ if(DEFINED OSL_ROOT)
lib
)
add_library(OSL::oslcomp SHARED IMPORTED)
set_target_properties(OSL::oslcomp PROPERTIES
IMPORTED_LOCATION ${oslcomp_LIBRARY}
)
# Find the oslexec library.
find_library(oslexec_LIBRARY
NAMES
@@ -44,8 +86,15 @@ if(DEFINED OSL_ROOT)
lib
)
add_library(OSL::oslexec SHARED IMPORTED)
set_target_properties(OSL::oslexec PROPERTIES
IMPORTED_LOCATION ${oslexec_LIBRARY}
)
set(OSL_SHADERS_INCLUDE_DIR ${OSL_ROOT}/share)
# Variable used by the OSL unit tests.
set(OSL_SHADERS_DIR ${OSL_ROOT}/share/OSL/shaders)
set(OSL_SHADERS_DIR ${OSL_SHADERS_INCLUDE_DIR}/OSL/shaders)
if(EXISTS "${OSL_SHADERS_DIR}")
@@ -56,6 +105,15 @@ if(DEFINED OSL_ROOT)
endif()
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (OpenShadingLanguage
FOUND_VAR OpenShadingLanguage_FOUND
REQUIRED_VARS OSL_INCLUDE_DIR oslcomp_LIBRARY oslexec_LIBRARY OpenShadingLanguage_VERSION
VERSION_VAR OpenShadingLanguage_VERSION
)
set(OSL_FOUND ${OpenShadingLanguage_FOUND})
endif()
###############################################################################
@@ -64,16 +122,21 @@ endif()
if(OSL_FOUND)
if (NOT OSL_FIND_QUIETLY)
message(STATUS "OpenShadingLanguage includes = ${OSL_INCLUDE_DIR}")
message(STATUS "OpenShadingLanguage oslcomp library = ${oslcomp_LIBRARY}")
message(STATUS "OpenShadingLanguage oslexec library = ${oslexec_LIBRARY}")
message(STATUS "OpenShadingLanguage includes = ${OSL_INCLUDE_DIR}")
message(STATUS "OpenShadingLanguage shaders = ${OSL_SHADERS_DIR}")
message(STATUS "OpenShadingLanguage library dir = ${OSL_LIB_DIR}")
endif ()
set_target_properties(osl::osl PROPERTIES
IMPORTED_LOCATION ${oslcomp_LIBRARY}
IMPORTED_LOCATION ${oslexec_LIBRARY}
INTERFACE_INCLUDE_DIRECTORIES ${OSL_INCLUDE_DIR}
)
list(APPEND LIB_INCLUDE_DIRS ${OSL_INCLUDE_DIR})
list(APPEND LIB_INCLUDE_DIRS ${OSL_SHADERS_INCLUDE_DIR})
target_include_directories(osl::osl INTERFACE "${LIB_INCLUDE_DIRS}")
target_link_libraries(osl::osl INTERFACE OSL::oslcomp OSL::oslexec)
if (${OpenShadingLanguage_VERSION} VERSION_GREATER_EQUAL "1.12" AND ${CMAKE_CXX_STANDARD} LESS_EQUAL 11)
set(OSL_FOUND OFF)
message(WARNING "Need C++14 or higher to compile OpenShadingLanguage. Skipping build the OSL unit tests")
endif()
mark_as_advanced(OSL_INCLUDE_DIR
oslcomp_LIBRARY oslcomp_FOUND
+33
View File
@@ -34,7 +34,40 @@ if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL)
endif()
if(expat_FOUND)
if (TARGET expat::libexpat)
message(STATUS "Expat ${expat_VERSION} detected, aliasing targets.")
add_library(expat::expat ALIAS expat::libexpat)
endif()
get_target_property(expat_INCLUDE_DIR expat::expat INTERFACE_INCLUDE_DIRECTORIES)
get_target_property(expat_LIBRARY expat::expat LOCATION)
if (NOT expat_INCLUDE_DIR)
# Find include directory too, as its Config module doesn't include it
find_path(expat_INCLUDE_DIR
NAMES
expat.h
HINTS
${expat_ROOT}
${PC_expat_INCLUDE_DIRS}
PATH_SUFFIXES
include
expat/include
)
message(WARNING "Expat's include directory not specified in its Config module, patching it now to ${expat_INCLUDE_DIR}.")
if (TARGET expat::libexpat)
set_target_properties(expat::libexpat PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${expat_INCLUDE_DIR}
)
else()
set_target_properties(expat::expat PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${expat_INCLUDE_DIR}
)
endif()
endif()
set(_expat_REQUIRED_VARS ${expat_REQUIRED_VARS} expat_INCLUDE_DIR)
else()
list(APPEND _expat_REQUIRED_VARS expat_INCLUDE_DIR)
+4 -4
View File
@@ -60,19 +60,19 @@ if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL)
# Lib names to search for
set(_yaml-cpp_LIB_NAMES yaml-cpp)
if(WIN32 AND BUILD_TYPE_DEBUG)
if(WIN32 AND BUILD_TYPE_DEBUG AND NOT MINGW)
# Prefer Debug lib names (Windows only)
list(INSERT _yaml-cpp_LIB_NAMES 0 yaml-cppd)
endif()
if(yaml-cpp_STATIC_LIBRARY)
# Prefer static lib names
if(WIN32)
if(WIN32 AND NOT MINGW)
set(_yaml-cpp_LIB_SUFFIX "md")
endif()
set(_yaml-cpp_STATIC_LIB_NAMES
"libyaml-cpp${_yaml-cpp_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}")
if(WIN32 AND BUILD_TYPE_DEBUG)
if(WIN32 AND BUILD_TYPE_DEBUG AND NOT MINGW)
# Prefer static Debug lib names (Windows only)
list(INSERT _yaml-cpp_STATIC_LIB_NAMES 0
"libyaml-cpp${_yaml-cpp_LIB_SUFFIX}d${CMAKE_STATIC_LIBRARY_SUFFIX}")
@@ -144,7 +144,7 @@ if(NOT yaml-cpp_FOUND)
#set(yaml-cpp_INCLUDE_DIR "${_EXT_DIST_ROOT}/${CMAKE_INSTALL_INCLUDEDIR}")
# Set the expected library name
if(WIN32)
if(WIN32 AND NOT MINGW)
set(_yaml-cpp_LIB_SUFFIX "md")
if(BUILD_TYPE_DEBUG)
string(APPEND _yaml-cpp_LIB_SUFFIX "d")
+6 -2
View File
@@ -25,6 +25,10 @@ if(USE_MSVC)
# Note: Do not use /Wall (i.e. /W4) which adds 'informational' warnings.
set(PLATFORM_COMPILE_FLAGS "${PLATFORM_COMPILE_FLAGS} /W3")
# Do enable C4701 (Potentially uninitialized local variable 'name' used), which is level 4.
# This is because strtoX-based from_chars leave the value variable unmodified.
set(PLATFORM_COMPILE_FLAGS "${PLATFORM_COMPILE_FLAGS} /we4701")
if(OCIO_WARNING_AS_ERROR)
set(PLATFORM_COMPILE_FLAGS "${PLATFORM_COMPILE_FLAGS} /WX")
endif()
@@ -98,8 +102,8 @@ if (UNIX AND NOT CMAKE_SKIP_RPATH)
# (i.e. a binary loading a dynamic library) and then from the current directory
# (i.e. dynamic library loading another dynamic library).
if (APPLE)
set(CMAKE_INSTALL_RPATH "@loader_path/../lib;@loader_path")
set(CMAKE_INSTALL_RPATH "@loader_path/../${CMAKE_INSTALL_LIBDIR};@loader_path")
else()
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib;$ORIGIN")
set(CMAKE_INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR};$ORIGIN")
endif()
endif()
+238 -214
View File
@@ -2,179 +2,178 @@
# Copyright Contributors to the OpenColorIO Project.
set(SOURCES
apphelpers/CategoryHelpers.cpp
apphelpers/ColorSpaceHelpers.cpp
apphelpers/DisplayViewHelpers.cpp
apphelpers/LegacyViewingPipeline.cpp
apphelpers/MixingHelpers.cpp
Baker.cpp
BitDepthUtils.cpp
Caching.cpp
ColorSpace.cpp
ColorSpaceSet.cpp
Config.cpp
Context.cpp
ContextVariableUtils.cpp
CPUProcessor.cpp
Display.cpp
DynamicProperty.cpp
Exception.cpp
fileformats/cdl/CDLParser.cpp
fileformats/cdl/CDLReaderHelper.cpp
fileformats/cdl/CDLWriter.cpp
fileformats/ctf/CTFReaderHelper.cpp
fileformats/ctf/CTFReaderUtils.cpp
fileformats/ctf/CTFTransform.cpp
fileformats/ctf/IndexMapping.cpp
fileformats/FileFormat3DL.cpp
fileformats/FileFormatCCC.cpp
fileformats/FileFormatCC.cpp
fileformats/FileFormatCDL.cpp
fileformats/FileFormatCSP.cpp
fileformats/FileFormatCTF.cpp
fileformats/FileFormatDiscreet1DL.cpp
fileformats/FileFormatHDL.cpp
fileformats/FileFormatICC.cpp
fileformats/FileFormatIridasCube.cpp
fileformats/FileFormatIridasItx.cpp
fileformats/FileFormatIridasLook.cpp
fileformats/FileFormatPandora.cpp
fileformats/FileFormatResolveCube.cpp
fileformats/FileFormatSpi1D.cpp
fileformats/FileFormatSpi3D.cpp
fileformats/FileFormatSpiMtx.cpp
fileformats/FileFormatTruelight.cpp
fileformats/FileFormatUtils.cpp
fileformats/FileFormatVF.cpp
fileformats/FormatMetadata.cpp
fileformats/xmlutils/XMLReaderHelper.cpp
fileformats/xmlutils/XMLReaderUtils.cpp
fileformats/xmlutils/XMLWriterUtils.cpp
FileRules.cpp
GPUProcessor.cpp
GpuShader.cpp
GpuShaderDesc.cpp
GpuShaderUtils.cpp
HashUtils.cpp
ImageDesc.cpp
ImagePacking.cpp
Logging.cpp
Look.cpp
LookParse.cpp
MathUtils.cpp
md5/md5.cpp
NamedTransform.cpp
OCIOYaml.cpp
Op.cpp
OpOptimizers.cpp
ops/allocation/AllocationOp.cpp
ops/cdl/CDLOpCPU.cpp
ops/cdl/CDLOpData.cpp
ops/cdl/CDLOpGPU.cpp
ops/cdl/CDLOp.cpp
ops/exponent/ExponentOp.cpp
ops/exposurecontrast/ExposureContrastOpCPU.cpp
ops/exposurecontrast/ExposureContrastOpData.cpp
ops/exposurecontrast/ExposureContrastOpGPU.cpp
ops/exposurecontrast/ExposureContrastOp.cpp
ops/fixedfunction/FixedFunctionOpCPU.cpp
ops/fixedfunction/FixedFunctionOpData.cpp
ops/fixedfunction/FixedFunctionOpGPU.cpp
ops/fixedfunction/FixedFunctionOp.cpp
ops/gamma/GammaOpCPU.cpp
ops/gamma/GammaOpData.cpp
ops/gamma/GammaOpGPU.cpp
ops/gamma/GammaOpUtils.cpp
ops/gamma/GammaOp.cpp
ops/gradingprimary/GradingPrimary.cpp
ops/gradingprimary/GradingPrimaryOpCPU.cpp
ops/gradingprimary/GradingPrimaryOpData.cpp
ops/gradingprimary/GradingPrimaryOpGPU.cpp
ops/gradingprimary/GradingPrimaryOp.cpp
ops/gradingrgbcurve/GradingBSplineCurve.cpp
ops/gradingrgbcurve/GradingRGBCurveOpCPU.cpp
ops/gradingrgbcurve/GradingRGBCurveOpData.cpp
ops/gradingrgbcurve/GradingRGBCurveOpGPU.cpp
ops/gradingrgbcurve/GradingRGBCurveOp.cpp
ops/gradingrgbcurve/GradingRGBCurve.cpp
ops/gradingtone/GradingTone.cpp
ops/gradingtone/GradingToneOpCPU.cpp
ops/gradingtone/GradingToneOpData.cpp
ops/gradingtone/GradingToneOpGPU.cpp
ops/gradingtone/GradingToneOp.cpp
ops/log/LogOpCPU.cpp
ops/log/LogOpData.cpp
ops/log/LogOpGPU.cpp
ops/log/LogOp.cpp
ops/log/LogUtils.cpp
ops/lut1d/Lut1DOp.cpp
ops/lut1d/Lut1DOpCPU.cpp
ops/lut1d/Lut1DOpData.cpp
ops/lut1d/Lut1DOpGPU.cpp
ops/lut3d/Lut3DOp.cpp
ops/lut3d/Lut3DOpCPU.cpp
ops/lut3d/Lut3DOpData.cpp
ops/lut3d/Lut3DOpGPU.cpp
ops/matrix/MatrixOpCPU.cpp
ops/matrix/MatrixOpData.cpp
ops/matrix/MatrixOpGPU.cpp
ops/matrix/MatrixOp.cpp
ops/noop/NoOps.cpp
ops/OpTools.cpp
ops/range/RangeOpCPU.cpp
ops/range/RangeOpData.cpp
ops/range/RangeOpGPU.cpp
ops/range/RangeOp.cpp
ops/reference/ReferenceOpData.cpp
ParseUtils.cpp
PathUtils.cpp
Platform.cpp
Processor.cpp
ScanlineHelper.cpp
Transform.cpp
transforms/AllocationTransform.cpp
transforms/builtins/ACES.cpp
transforms/builtins/BuiltinTransformRegistry.cpp
transforms/builtins/ColorMatrixHelpers.cpp
transforms/builtins/OpHelpers.cpp
transforms/builtins/ArriCameras.cpp
transforms/builtins/CanonCameras.cpp
transforms/builtins/Displays.cpp
transforms/builtins/PanasonicCameras.cpp
transforms/builtins/RedCameras.cpp
transforms/builtins/SonyCameras.cpp
transforms/BuiltinTransform.cpp
transforms/CDLTransform.cpp
transforms/ColorSpaceTransform.cpp
transforms/DisplayViewTransform.cpp
transforms/ExponentTransform.cpp
transforms/ExponentWithLinearTransform.cpp
transforms/ExposureContrastTransform.cpp
transforms/FileTransform.cpp
transforms/FixedFunctionTransform.cpp
transforms/GradingPrimaryTransform.cpp
transforms/GradingRGBCurveTransform.cpp
transforms/GradingToneTransform.cpp
transforms/GroupTransform.cpp
transforms/LogAffineTransform.cpp
transforms/LogCameraTransform.cpp
transforms/LogTransform.cpp
transforms/LookTransform.cpp
transforms/Lut1DTransform.cpp
transforms/Lut3DTransform.cpp
transforms/MatrixTransform.cpp
transforms/RangeTransform.cpp
ViewingRules.cpp
ViewTransform.cpp
SystemMonitor.cpp
apphelpers/CategoryHelpers.cpp
apphelpers/ColorSpaceHelpers.cpp
apphelpers/DisplayViewHelpers.cpp
apphelpers/LegacyViewingPipeline.cpp
apphelpers/MixingHelpers.cpp
Baker.cpp
BitDepthUtils.cpp
Caching.cpp
ColorSpace.cpp
ColorSpaceSet.cpp
Config.cpp
Context.cpp
ContextVariableUtils.cpp
CPUProcessor.cpp
Display.cpp
DynamicProperty.cpp
Exception.cpp
fileformats/cdl/CDLParser.cpp
fileformats/cdl/CDLReaderHelper.cpp
fileformats/cdl/CDLWriter.cpp
fileformats/ctf/CTFReaderHelper.cpp
fileformats/ctf/CTFReaderUtils.cpp
fileformats/ctf/CTFTransform.cpp
fileformats/ctf/IndexMapping.cpp
fileformats/FileFormat3DL.cpp
fileformats/FileFormatCCC.cpp
fileformats/FileFormatCC.cpp
fileformats/FileFormatCDL.cpp
fileformats/FileFormatCSP.cpp
fileformats/FileFormatCTF.cpp
fileformats/FileFormatDiscreet1DL.cpp
fileformats/FileFormatHDL.cpp
fileformats/FileFormatICC.cpp
fileformats/FileFormatIridasCube.cpp
fileformats/FileFormatIridasItx.cpp
fileformats/FileFormatIridasLook.cpp
fileformats/FileFormatPandora.cpp
fileformats/FileFormatResolveCube.cpp
fileformats/FileFormatSpi1D.cpp
fileformats/FileFormatSpi3D.cpp
fileformats/FileFormatSpiMtx.cpp
fileformats/FileFormatTruelight.cpp
fileformats/FileFormatUtils.cpp
fileformats/FileFormatVF.cpp
fileformats/FormatMetadata.cpp
fileformats/xmlutils/XMLReaderHelper.cpp
fileformats/xmlutils/XMLReaderUtils.cpp
fileformats/xmlutils/XMLWriterUtils.cpp
FileRules.cpp
GPUProcessor.cpp
GpuShader.cpp
GpuShaderDesc.cpp
GpuShaderClassWrapper.cpp
GpuShaderUtils.cpp
HashUtils.cpp
ImageDesc.cpp
ImagePacking.cpp
Logging.cpp
Look.cpp
LookParse.cpp
MathUtils.cpp
md5/md5.cpp
NamedTransform.cpp
OCIOYaml.cpp
Op.cpp
OpOptimizers.cpp
ops/allocation/AllocationOp.cpp
ops/cdl/CDLOpCPU.cpp
ops/cdl/CDLOpData.cpp
ops/cdl/CDLOpGPU.cpp
ops/cdl/CDLOp.cpp
ops/exponent/ExponentOp.cpp
ops/exposurecontrast/ExposureContrastOpCPU.cpp
ops/exposurecontrast/ExposureContrastOpData.cpp
ops/exposurecontrast/ExposureContrastOpGPU.cpp
ops/exposurecontrast/ExposureContrastOp.cpp
ops/fixedfunction/FixedFunctionOpCPU.cpp
ops/fixedfunction/FixedFunctionOpData.cpp
ops/fixedfunction/FixedFunctionOpGPU.cpp
ops/fixedfunction/FixedFunctionOp.cpp
ops/gamma/GammaOpCPU.cpp
ops/gamma/GammaOpData.cpp
ops/gamma/GammaOpGPU.cpp
ops/gamma/GammaOpUtils.cpp
ops/gamma/GammaOp.cpp
ops/gradingprimary/GradingPrimary.cpp
ops/gradingprimary/GradingPrimaryOpCPU.cpp
ops/gradingprimary/GradingPrimaryOpData.cpp
ops/gradingprimary/GradingPrimaryOpGPU.cpp
ops/gradingprimary/GradingPrimaryOp.cpp
ops/gradingrgbcurve/GradingBSplineCurve.cpp
ops/gradingrgbcurve/GradingRGBCurveOpCPU.cpp
ops/gradingrgbcurve/GradingRGBCurveOpData.cpp
ops/gradingrgbcurve/GradingRGBCurveOpGPU.cpp
ops/gradingrgbcurve/GradingRGBCurveOp.cpp
ops/gradingrgbcurve/GradingRGBCurve.cpp
ops/gradingtone/GradingTone.cpp
ops/gradingtone/GradingToneOpCPU.cpp
ops/gradingtone/GradingToneOpData.cpp
ops/gradingtone/GradingToneOpGPU.cpp
ops/gradingtone/GradingToneOp.cpp
ops/log/LogOpCPU.cpp
ops/log/LogOpData.cpp
ops/log/LogOpGPU.cpp
ops/log/LogOp.cpp
ops/log/LogUtils.cpp
ops/lut1d/Lut1DOp.cpp
ops/lut1d/Lut1DOpCPU.cpp
ops/lut1d/Lut1DOpData.cpp
ops/lut1d/Lut1DOpGPU.cpp
ops/lut3d/Lut3DOp.cpp
ops/lut3d/Lut3DOpCPU.cpp
ops/lut3d/Lut3DOpData.cpp
ops/lut3d/Lut3DOpGPU.cpp
ops/matrix/MatrixOpCPU.cpp
ops/matrix/MatrixOpData.cpp
ops/matrix/MatrixOpGPU.cpp
ops/matrix/MatrixOp.cpp
ops/noop/NoOps.cpp
ops/OpTools.cpp
ops/range/RangeOpCPU.cpp
ops/range/RangeOpData.cpp
ops/range/RangeOpGPU.cpp
ops/range/RangeOp.cpp
ops/reference/ReferenceOpData.cpp
ParseUtils.cpp
PathUtils.cpp
Platform.cpp
Processor.cpp
ScanlineHelper.cpp
Transform.cpp
transforms/AllocationTransform.cpp
transforms/builtins/ACES.cpp
transforms/builtins/BuiltinTransformRegistry.cpp
transforms/builtins/ColorMatrixHelpers.cpp
transforms/builtins/OpHelpers.cpp
transforms/builtins/ArriCameras.cpp
transforms/builtins/CanonCameras.cpp
transforms/builtins/Displays.cpp
transforms/builtins/PanasonicCameras.cpp
transforms/builtins/RedCameras.cpp
transforms/builtins/SonyCameras.cpp
transforms/BuiltinTransform.cpp
transforms/CDLTransform.cpp
transforms/ColorSpaceTransform.cpp
transforms/DisplayViewTransform.cpp
transforms/ExponentTransform.cpp
transforms/ExponentWithLinearTransform.cpp
transforms/ExposureContrastTransform.cpp
transforms/FileTransform.cpp
transforms/FixedFunctionTransform.cpp
transforms/GradingPrimaryTransform.cpp
transforms/GradingRGBCurveTransform.cpp
transforms/GradingToneTransform.cpp
transforms/GroupTransform.cpp
transforms/LogAffineTransform.cpp
transforms/LogCameraTransform.cpp
transforms/LogTransform.cpp
transforms/LookTransform.cpp
transforms/Lut1DTransform.cpp
transforms/Lut3DTransform.cpp
transforms/MatrixTransform.cpp
transforms/RangeTransform.cpp
ViewingRules.cpp
ViewTransform.cpp
SystemMonitor.cpp
)
if(NOT WIN32)
# Install the pkg-config file.
include(GNUInstallDirs)
set(prefix ${CMAKE_INSTALL_PREFIX})
set(exec_prefix "\${prefix}")
set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
@@ -191,74 +190,88 @@ target_compile_features(OpenColorIO
)
if(BUILD_SHARED_LIBS AND WIN32)
# Impose a versioned name on Windows to avoid binary name clashes.
set(OCIO_LIBNAME_SUFFIX
${OCIO_LIBNAME_SUFFIX}_${OpenColorIO_VERSION_MAJOR}_${OpenColorIO_VERSION_MINOR}
)
set(CMAKE_SHARED_LIBRARY_SUFFIX ${OCIO_LIBNAME_SUFFIX}.dll)
# Only use the versioned name with the dynamic library.
set(CMAKE_SHARED_LIBRARY_SUFFIX _${OpenColorIO_VERSION_MAJOR}_${OpenColorIO_VERSION_MINOR}.dll)
# Create the version.rc file for the Windows DLL.
configure_file(res/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY)
set(SOURCES ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
endif()
set(HEADER_LOCATION "${CMAKE_SOURCE_DIR}/include/OpenColorIO")
file(GLOB_RECURSE INSTALL_HEADERS "${HEADER_LOCATION}/*.h")
# Some part of the build process expect to find the ABI header here,
# notably the documentation.
set(ABI_HEADER_LOCATION "${CMAKE_BINARY_DIR}/include/OpenColorIO")
list(APPEND INSTALL_HEADERS ${ABI_HEADER_LOCATION}/OpenColorABI.h)
configure_file("${HEADER_LOCATION}/OpenColorABI.h.in" "${ABI_HEADER_LOCATION}/OpenColorABI.h" @ONLY)
set(BUILD_INCLUDES
${HEADER_LOCATION}/..
${HEADER_LOCATION}
${CMAKE_CURRENT_SOURCE_DIR}
${ABI_HEADER_LOCATION}
)
target_include_directories(OpenColorIO
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PUBLIC
"$<BUILD_INTERFACE:${BUILD_INCLUDES}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
target_link_libraries(OpenColorIO
PUBLIC
OpenColorIOHeaders
PRIVATE
expat::expat
${OCIO_HALF_LIB}
pystring::pystring
sampleicc::sampleicc
utils::strings
yaml-cpp
PRIVATE
expat::expat
${OCIO_HALF_LIB}
pystring::pystring
sampleicc::sampleicc
utils::from_chars
utils::strings
yaml-cpp
)
if(APPLE)
target_link_libraries(OpenColorIO
PRIVATE
"-framework Carbon"
"-framework IOKit"
)
target_link_libraries(OpenColorIO
PRIVATE
"-framework Carbon"
"-framework IOKit"
)
endif()
if(NOT BUILD_SHARED_LIBS)
target_compile_definitions(OpenColorIO
PRIVATE
OpenColorIO_SKIP_IMPORTS
)
target_compile_definitions(OpenColorIO
PRIVATE
OpenColorIO_SKIP_IMPORTS
)
else()
# Only exports selected symbols.
target_compile_definitions(OpenColorIO
PRIVATE
OpenColorIO_EXPORTS
)
# Only exports selected symbols.
target_compile_definitions(OpenColorIO
PRIVATE
OpenColorIO_EXPORTS
)
endif()
if(BUILD_SHARED_LIBS OR (OCIO_BUILD_PYTHON AND UNIX))
# The Python bindings is a 'module' which is a dynamic library on Linux
# (i.e. '-fPIC' needed), but a static library on Windows.
# The Python bindings is a 'module' which is a dynamic library on Linux
# (i.e. '-fPIC' needed), but a static library on Windows.
# If supported for the target machine, emit position-independent code
# suitable for dynamic linking.
set_property(TARGET OpenColorIO PROPERTY POSITION_INDEPENDENT_CODE ON)
# If supported for the target machine, emit position-independent code
# suitable for dynamic linking.
set_property(TARGET OpenColorIO PROPERTY POSITION_INDEPENDENT_CODE ON)
endif()
if(OCIO_USE_SSE)
target_compile_definitions(OpenColorIO
PRIVATE
USE_SSE
)
target_compile_definitions(OpenColorIO
PRIVATE
USE_SSE
)
endif()
if(MSVC AND BUILD_TYPE_DEBUG AND BUILD_SHARED_LIBS)
set_target_properties(OpenColorIO PROPERTIES
PDB_NAME ${PROJECT_NAME}${OCIO_LIBNAME_SUFFIX}
PDB_NAME ${PROJECT_NAME}${OCIO_LIBNAME_SUFFIX}_${OpenColorIO_VERSION_MAJOR}_${OpenColorIO_VERSION_MINOR}
)
endif()
@@ -269,13 +282,23 @@ if(WIN32)
PRIVATE
XML_STATIC
)
if (OCIO_USE_WINDOWS_UNICODE)
# Add Unicode definitions to use Unicode functions
target_compile_definitions(OpenColorIO
PRIVATE
UNICODE
_UNICODE
)
endif()
endif()
set_target_properties(OpenColorIO PROPERTIES
OUTPUT_NAME ${PROJECT_NAME}
OUTPUT_NAME ${PROJECT_NAME}${OCIO_LIBNAME_SUFFIX}
COMPILE_FLAGS "${PLATFORM_COMPILE_FLAGS}"
VERSION ${OpenColorIO_VERSION}
SOVERSION ${SOVERSION}
PUBLIC_HEADER "${INSTALL_HEADERS}"
)
if (UNIX AND NOT APPLE)
@@ -287,13 +310,14 @@ if (UNIX AND NOT APPLE)
endif ()
if(MSVC AND BUILD_SHARED_LIBS)
# Install the pdb file if any.
install(FILES $<TARGET_PDB_FILE:${PROJECT_NAME}> DESTINATION bin OPTIONAL)
# Install the pdb file if any.
install(FILES $<TARGET_PDB_FILE:${PROJECT_NAME}> DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL)
endif()
install(TARGETS OpenColorIO
EXPORT ${PROJECT_NAME}_EXPORTED_TARGETS
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
ARCHIVE DESTINATION lib
EXPORT ${PROJECT_NAME}_EXPORTED_TARGETS
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/OpenColorIO
)
+4 -5
View File
@@ -1117,7 +1117,7 @@ ConstConfigRcPtr Config::CreateFromFile(const char * filename)
throw ExceptionMissingFile ("The config filepath is missing.");
}
std::ifstream istream(filename);
std::ifstream istream = Platform::CreateInputFileStream(filename, std::ios_base::in);
if (istream.fail())
{
std::ostringstream os;
@@ -1737,7 +1737,7 @@ void Config::validate() const
if (!path || !*path)
{
errMsg += " The search_path is empty.";
break;
continue;
}
const std::string resolvedSearchPath = getImpl()->m_context->resolveStringVar(path);
@@ -1755,17 +1755,16 @@ void Config::validate() const
}
oss << ".";
errMsg += oss.str();
break;
continue;
}
foundOne = true;
}
// After looping over all the search paths, none of them can be successfully resolved.
if (!foundOne)
{
// No valid paths were found.
getImpl()->m_validationtext = errMsg;
throw Exception(errMsg.c_str());
}
+25
View File
@@ -6,6 +6,7 @@
#include "ContextVariableUtils.h"
#include "utils/StringUtils.h"
#include "Platform.h"
#if defined(__APPLE__) && !defined(__IPHONE__)
@@ -19,6 +20,12 @@ extern char ** environ;
namespace
{
#if defined(_WIN32) && defined(UNICODE)
inline wchar_t ** GetEnviron()
{
return _wenviron;
}
#else
inline char ** GetEnviron()
{
#if __IPHONE__
@@ -30,6 +37,7 @@ inline char ** GetEnviron()
return environ;
#endif
}
#endif
} // anon.
@@ -71,11 +79,28 @@ void LoadEnvironment(EnvMap & map, bool update)
{
// First, add or update the context variables with existing env. variables.
#if defined(_WIN32) && defined(UNICODE)
if (GetEnviron() == NULL) {
// If the program starts with "main" instead of "wmain", then wenviron returns NULL until
// the first call to either wgetenv or wputenv. Calling wgetenv, even with an empty
// variable name, will populate wenviron correctly. We also use wgetenv_s (which requires
// a valid size pointer) to suppress safety warnings about wgetenv during the compile.
size_t sz;
_wgetenv_s(&sz, NULL, 0, L"");
}
for (wchar_t **env = GetEnviron(); *env != NULL; ++env)
{
// Split environment up into std::map[name] = value.
const std::string env_str = Platform::Utf16ToUtf8((wchar_t*)*env);
#else
for (char **env = GetEnviron(); *env != NULL; ++env)
{
// Split environment up into std::map[name] = value.
const std::string env_str = (char*)*env;
#endif
const int pos = static_cast<int>(env_str.find_first_of('='));
const std::string name = env_str.substr(0, pos);
+287
View File
@@ -0,0 +1,287 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenColorIO Project.
#include <OpenColorIO/OpenColorIO.h>
#include "GpuShaderClassWrapper.h"
namespace OCIO_NAMESPACE
{
std::string GetArrayLengthVariableName(const std::string& variableName)
{
return variableName + "_count";
}
std::string MetalShaderClassWrapper::generateClassWrapperHeader(GpuShaderText& kw) const
{
if(m_className.empty())
{
throw Exception("Struct name must include at least 1 character");
}
if(std::isdigit(m_className[0]))
{
throw Exception(("Struct name must not start with a digit. Invalid className passed in: " + m_className).c_str());
}
kw.newLine() << "struct " << m_className;
kw.newLine() << "{";
kw.newLine() << m_className <<"(";
kw.indent();
std::string separator = "";
for(const auto& param : m_functionParameters)
{
kw.newLine() << separator << (param.m_isArray ? "constant " : "") << param.m_type << " " << param.m_name;
if(param.m_isArray)
{
kw.newLine() << ", int " << GetArrayLengthVariableName(param.m_name.substr(0, param.m_name.find('[')));
}
separator = ", ";
}
kw.dedent();
kw.newLine() << ")";
kw.newLine() << "{";
kw.indent();
for(const auto& param : m_functionParameters)
{
size_t openAngledBracketPos = param.m_name.find('[');
if(!param.m_isArray)
{
kw.newLine() << "this->" << param.m_name << " = " << param.m_name << ";";
}
else
{
size_t closeAngledBracketPos = param.m_name.find(']');
std::string variableName = param.m_name.substr(0, openAngledBracketPos);
kw.newLine() << "for(int i = 0; i < "
<< GetArrayLengthVariableName(variableName)
<< "; ++i)";
kw.newLine() << "{";
kw.indent();
kw.newLine() << "this->" << variableName << "[i] = " << variableName << "[i];";
kw.dedent();
kw.newLine() << "}";
kw.newLine() << "for(int i = "
<< GetArrayLengthVariableName(variableName)
<< "; i < "
<< param.m_name.substr(openAngledBracketPos+1, closeAngledBracketPos-openAngledBracketPos-1)
<< "; ++i)";
kw.newLine() << "{";
kw.indent();
kw.newLine() << "this->" << variableName << "[i] = 0;";
kw.dedent();
kw.newLine() << "}";
}
}
kw.dedent();
kw.newLine() <<"}";
return kw.string();
}
std::string MetalShaderClassWrapper::generateClassWrapperFooter(GpuShaderText& kw, const std::string &ocioFunctionName) const
{
if(m_className.empty())
{
throw Exception("Struct name must include at least 1 character");
}
if(std::isdigit(m_className[0]))
{
throw Exception(("Struct name must not start with a digit. Invalid className passed in: " + m_className).c_str());
}
kw.newLine() << "};";
kw.newLine() << kw.float4Keyword() << " " << ocioFunctionName<< "(";
std::string texParamOut;
kw.indent();
std::string separator = "";
for(const auto& param : m_functionParameters)
{
kw.newLine() << separator << (param.m_isArray ? "constant " : "") << param.m_type << " " << param.m_name;
if(param.m_isArray)
{
kw.newLine() << ", int " << GetArrayLengthVariableName(param.m_name.substr(0, param.m_name.find('[')));
}
separator = ", ";
}
kw.newLine() << separator << kw.float4Keyword() << " inPixel)";
kw.dedent();
kw.newLine() << "{";
kw.indent();
kw.newLine() << "return " << m_className << "(";
kw.indent();
separator = "";
for(const auto& param : m_functionParameters)
{
size_t openAngledBracketPos = param.m_name.find('[');
bool isArray = openAngledBracketPos != std::string::npos;
if(!isArray)
{
kw.newLine() << separator << param.m_name;
}
else
{
kw.newLine() << separator << param.m_name.substr(0, openAngledBracketPos);
kw.newLine() << ", " << GetArrayLengthVariableName(param.m_name.substr(0, openAngledBracketPos));
}
separator = ", ";
}
kw.dedent();
kw.newLine() << ")." << ocioFunctionName << "(inPixel);";
kw.dedent();
kw.newLine() << "}";
return kw.string();
}
std::string MetalShaderClassWrapper::getClassWrapperName(const std::string &resourcePrefix, const std::string& functionName)
{
return (resourcePrefix.length() == 0 ? "OCIO_" : resourcePrefix) + functionName;
}
void MetalShaderClassWrapper::extractFunctionParameters(const std::string& declaration)
{
// We want the caller to always pass 3d luts first with their samplers, and then pass other luts.
std::vector<std::tuple<std::string, std::string, std::string>> lut3DTextures;
std::vector<std::tuple<std::string, std::string, std::string>> lutTextures;
std::vector<std::pair <std::string, std::string >> uniforms;
m_functionParameters.clear();
std::string lineBuffer;
std::istringstream is(declaration);
while(!is.eof())
{
std::getline(is, lineBuffer);
if(lineBuffer.empty())
continue;
size_t i = 0;
// Skip spaces
while(std::isspace(lineBuffer[i])) ++i;
// if the line was all skippable characters
if(i >= lineBuffer.size())
continue;
// if the line is a comment
if(lineBuffer[i + 0] == '/' && lineBuffer[i + 1] == '/')
continue;
if(lineBuffer.compare(i, 7, "texture") == 0)
{
int textureDim = static_cast<int>(lineBuffer[i+7] - '0');
size_t endTextureType = lineBuffer.find('>');
std::string textureType = lineBuffer.substr(i, (endTextureType - i + 1));
i = endTextureType + 1;
while(std::isspace(lineBuffer[i])) ++i;
size_t endTextureName = lineBuffer.find_first_of(" \t;", i);
std::string textureName = lineBuffer.substr(i, (endTextureName - i));
std::getline(is, lineBuffer);
i = lineBuffer.find("sampler") + 7;
while(std::isspace(lineBuffer[i])) ++i;
size_t endSamplerName = lineBuffer.find_first_of(" \t;", i);
std::string samplerName = lineBuffer.substr(i, endSamplerName - i);
if(textureDim == 3)
lut3DTextures.emplace_back(textureType, textureName, samplerName);
else
lutTextures.emplace_back(textureType, textureName, samplerName);
}
else
{
size_t endTypeName = lineBuffer.find_first_of(" \t", i);
std::string variableType = lineBuffer.substr(i, (endTypeName - i));
i = endTypeName + 1;
while(std::isspace(lineBuffer[i])) ++i;
size_t endVariableName = lineBuffer.find_first_of(" \t;", i);
std::string variableName = lineBuffer.substr(i, (endVariableName - i));
uniforms.emplace_back(variableType, variableName);
}
}
for(const auto& lut3D : lut3DTextures)
{
m_functionParameters.emplace_back(std::get<0>(lut3D).c_str(), std::get<1>(lut3D).c_str());
m_functionParameters.emplace_back("sampler", std::get<2>(lut3D).c_str());
}
for(const auto& lut : lutTextures)
{
m_functionParameters.emplace_back(std::get<0>(lut).c_str(), std::get<1>(lut).c_str());
m_functionParameters.emplace_back("sampler", std::get<2>(lut).c_str());
}
for(const auto& uniform : uniforms)
{
m_functionParameters.emplace_back(uniform.first, uniform.second);
}
}
void MetalShaderClassWrapper::prepareClassWrapper(const std::string& resourcePrefix, const std::string& functionName, const std::string& originalHeader)
{
m_functionName = functionName;
m_className = getClassWrapperName(resourcePrefix, functionName);
extractFunctionParameters(originalHeader);
}
std::string MetalShaderClassWrapper::getClassWrapperHeader(const std::string& originalHeader)
{
GpuShaderText st(GPU_LANGUAGE_MSL_2_0);
generateClassWrapperHeader(st);
st.newLine();
std::string classWrapHeader = "\n// Declaration of class wrapper\n\n";
classWrapHeader += st.string();
return classWrapHeader + originalHeader;
}
std::string MetalShaderClassWrapper::getClassWrapperFooter(const std::string& originalFooter)
{
GpuShaderText st(GPU_LANGUAGE_MSL_2_0);
st.newLine();
generateClassWrapperFooter(st, m_functionName);
std::string classWrapFooter = "\n// Close class wrapper\n\n";
classWrapFooter += st.string();
return originalFooter + classWrapFooter;
}
std::unique_ptr<GpuShaderClassWrapper> MetalShaderClassWrapper::clone() const
{
std::unique_ptr<MetalShaderClassWrapper> clonedWrapper = std::unique_ptr<MetalShaderClassWrapper>(new MetalShaderClassWrapper);
*clonedWrapper = *this;
return clonedWrapper;
}
MetalShaderClassWrapper& MetalShaderClassWrapper::operator=(const MetalShaderClassWrapper& rhs)
{
this->m_className = rhs.m_className;
this->m_functionName = rhs.m_functionName;
this->m_functionParameters = rhs.m_functionParameters;
return *this;
}
} // namespace OCIO_NAMESPACE
+88
View File
@@ -0,0 +1,88 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenColorIO Project.
#ifndef INCLUDED_OCIO_GPUSHADERCLASSWRAPPER_H
#define INCLUDED_OCIO_GPUSHADERCLASSWRAPPER_H
#include <sstream>
#include <utility>
#include <vector>
#include <memory>
#include <OpenColorIO/OpenColorIO.h>
#include "GpuShaderUtils.h"
namespace OCIO_NAMESPACE
{
class GpuShaderClassWrapper
{
public:
virtual void prepareClassWrapper(const std::string& resourcePrefix,
const std::string& functionName,
const std::string& originalHeader) = 0;
virtual std::string getClassWrapperHeader(const std::string& originalHeader) = 0;
virtual std::string getClassWrapperFooter(const std::string& originalFooter) = 0;
virtual std::unique_ptr<GpuShaderClassWrapper> clone() const = 0;
virtual ~GpuShaderClassWrapper() = default;
};
class NullGpuShaderClassWrapper : public GpuShaderClassWrapper
{
public:
void prepareClassWrapper(const std::string& /*resourcePrefix*/,
const std::string& /*functionName*/,
const std::string& /*originalHeader*/) final {}
std::string getClassWrapperHeader(const std::string& originalHeader) final { return originalHeader; }
std::string getClassWrapperFooter(const std::string& originalFooter) final { return originalFooter; }
std::unique_ptr<GpuShaderClassWrapper> clone() const final
{
return std::unique_ptr<NullGpuShaderClassWrapper>(new NullGpuShaderClassWrapper());
}
};
class MetalShaderClassWrapper : public GpuShaderClassWrapper
{
public:
void prepareClassWrapper(const std::string& resourcePrefix,
const std::string& functionName,
const std::string& originalHeader) final;
std::string getClassWrapperHeader(const std::string& originalHeader) final;
std::string getClassWrapperFooter(const std::string& originalFooter) final;
std::unique_ptr<GpuShaderClassWrapper> clone() const final;
MetalShaderClassWrapper& operator=(const MetalShaderClassWrapper& rhs);
private:
struct FunctionParam
{
FunctionParam(const std::string& type, const std::string& name) :
m_type(type),
m_name(name)
{
size_t openAngledBracketPos = name.find('[');
m_isArray = openAngledBracketPos != std::string::npos;
}
std::string m_type;
std::string m_name;
bool m_isArray;
};
std::string getClassWrapperName(const std::string &resourcePrefix, const std::string& functionName);
void extractFunctionParameters(const std::string& declaration);
std::string generateClassWrapperHeader(GpuShaderText& st) const;
std::string generateClassWrapperFooter(GpuShaderText& st, const std::string &ocioFunctionName) const;
std::string m_className;
std::string m_functionName;
std::vector<FunctionParam> m_functionParameters;
};
} // namespace OCIO_NAMESPACE
#endif
+52 -13
View File
@@ -2,12 +2,14 @@
// Copyright Contributors to the OpenColorIO Project.
#include <sstream>
#include <memory>
#include <OpenColorIO/OpenColorIO.h>
#include "DynamicProperty.h"
#include "GpuShader.h"
#include "GpuShaderUtils.h"
#include "GpuShaderClassWrapper.h"
#include "HashUtils.h"
#include "Logging.h"
#include "Mutex.h"
@@ -40,16 +42,18 @@ public:
std::string m_shaderCodeID;
std::vector<DynamicPropertyRcPtr> m_dynamicProperties;
std::unique_ptr<GpuShaderClassWrapper> m_classWrappingInterface;
Impl()
: m_functionName("OCIOMain")
, m_resourcePrefix("ocio")
, m_pixelName("outColor")
, m_classWrappingInterface(new NullGpuShaderClassWrapper)
{
}
~Impl()
{ }
~Impl() = default;
Impl(const Impl & rhs) = delete;
@@ -70,12 +74,34 @@ public:
m_functionHeader = rhs.m_functionHeader;
m_functionBody = rhs.m_functionBody;
m_functionFooter = rhs.m_functionFooter;
m_classWrappingInterface = rhs.m_classWrappingInterface->clone();
m_shaderCode.clear();
m_shaderCodeID.clear();
}
return *this;
}
static std::unique_ptr<GpuShaderClassWrapper> CreateClassWrapper(GpuLanguage language)
{
switch(language)
{
case GPU_LANGUAGE_MSL_2_0:
return std::unique_ptr<MetalShaderClassWrapper>(new MetalShaderClassWrapper);
case GPU_LANGUAGE_CG:
case GPU_LANGUAGE_GLSL_1_2:
case GPU_LANGUAGE_GLSL_1_3:
case GPU_LANGUAGE_GLSL_4_0:
case GPU_LANGUAGE_HLSL_DX11:
case LANGUAGE_OSL_1:
case GPU_LANGUAGE_GLSL_ES_1_0:
case GPU_LANGUAGE_GLSL_ES_3_0:
default:
return std::unique_ptr<NullGpuShaderClassWrapper>(new NullGpuShaderClassWrapper);
}
}
};
GpuShaderCreator::GpuShaderCreator()
@@ -104,7 +130,9 @@ const char * GpuShaderCreator::getUniqueID() const noexcept
void GpuShaderCreator::setLanguage(GpuLanguage lang) noexcept
{
AutoMutex lock(getImpl()->m_cacheIDMutex);
getImpl()->m_language = lang;
getImpl()->m_classWrappingInterface = Impl::CreateClassWrapper(getImpl()->m_language);
getImpl()->m_cacheID.clear();
}
@@ -281,7 +309,7 @@ void GpuShaderCreator::createShaderText(const char * shaderDeclarations,
AutoMutex lock(getImpl()->m_cacheIDMutex);
getImpl()->m_shaderCode.clear();
getImpl()->m_shaderCode += (shaderDeclarations && *shaderDeclarations) ? shaderDeclarations : "";
getImpl()->m_shaderCode += (shaderHelperMethods && *shaderHelperMethods) ? shaderHelperMethods : "";
getImpl()->m_shaderCode += (shaderFunctionHeader && *shaderFunctionHeader) ? shaderFunctionHeader : "";
@@ -308,14 +336,15 @@ void GpuShaderCreator::finalize()
kw.newLine() << "";
kw.newLine() << "/* All the generic helper methods */";
kw.newLine() << "";
kw.newLine() << "vector4 __operator__mul__(vector4 v, matrix m)";
kw.newLine() << "vector4 __operator__mul__(matrix m, vector4 v)";
kw.newLine() << "{";
kw.indent();
kw.newLine() << "return vector4(v.x * m[0][0] + v.y * m[1][0] + v.z * m[2][0] + v.w * m[3][0], "\
"v.x * m[0][1] + v.y * m[1][1] + v.z * m[2][1] + v.w * m[3][1], "\
"v.x * m[0][2] + v.y * m[1][2] + v.z * m[2][2] + v.w * m[3][2], "\
"v.x * m[0][3] + v.y * m[1][3] + v.z * m[2][3] + v.w * m[3][3]);";
kw.newLine() << "return vector4(v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3], ";
kw.newLine() << " v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3], ";
kw.newLine() << " v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2] + v.w * m[2][3], ";
kw.newLine() << " v.x * m[3][0] + v.y * m[3][1] + v.z * m[3][2] + v.w * m[3][3]);";
kw.dedent();
kw.newLine() << "}";
@@ -344,28 +373,32 @@ void GpuShaderCreator::finalize()
kw.newLine() << "}";
kw.newLine() << "";
kw.newLine() << "vector4 __operator__add__(vector4 v, color4 c) {";
kw.newLine() << "vector4 __operator__add__(vector4 v, color4 c)";
kw.newLine() << "{";
kw.indent();
kw.newLine() << "return v + vector4(c.rgb.r, c.rgb.g, c.rgb.b, c.a);";
kw.dedent();
kw.newLine() << "}";
kw.newLine() << "";
kw.newLine() << "vector4 __operator__add__(color4 c, vector4 v) {";
kw.newLine() << "vector4 __operator__add__(color4 c, vector4 v)";
kw.newLine() << "{";
kw.indent();
kw.newLine() << "return vector4(c.rgb.r, c.rgb.g, c.rgb.b, c.a) + v;";
kw.dedent();
kw.newLine() << "}";
kw.newLine() << "";
kw.newLine() << "vector4 pow(color4 c, vector4 v) {";
kw.newLine() << "vector4 pow(color4 c, vector4 v)";
kw.newLine() << "{";
kw.indent();
kw.newLine() << "return pow(vector4(c.rgb.r, c.rgb.g, c.rgb.b, c.a), v);";
kw.dedent();
kw.newLine() << "}";
kw.newLine() << "";
kw.newLine() << "vector4 max(vector4 v, color4 c) {";
kw.newLine() << "vector4 max(vector4 v, color4 c)";
kw.newLine() << "{";
kw.indent();
kw.newLine() << "return max(v, vector4(c.rgb.r, c.rgb.g, c.rgb.b, c.a));";
kw.dedent();
@@ -390,7 +423,13 @@ void GpuShaderCreator::finalize()
getImpl()->m_functionFooter += kw1.string();
}
getImpl()->m_classWrappingInterface->prepareClassWrapper(getResourcePrefix(),
getImpl()->m_functionName,
getImpl()->m_declarations);
getImpl()->m_declarations = getImpl()->m_classWrappingInterface->getClassWrapperHeader(getImpl()->m_declarations);
getImpl()->m_functionFooter = getImpl()->m_classWrappingInterface->getClassWrapperFooter(getImpl()->m_functionFooter);
createShaderText(getImpl()->m_declarations.c_str(),
getImpl()->m_helperMethods.c_str(),
+140 -30
View File
@@ -9,7 +9,6 @@
#include "MathUtils.h"
#include "utils/StringUtils.h"
namespace OCIO_NAMESPACE
{
// This method converts a float/double to a string adding a dot when
@@ -44,6 +43,8 @@ std::string getVecKeyword(GpuLanguage lang)
case GPU_LANGUAGE_GLSL_1_2:
case GPU_LANGUAGE_GLSL_1_3:
case GPU_LANGUAGE_GLSL_4_0:
case GPU_LANGUAGE_GLSL_ES_1_0:
case GPU_LANGUAGE_GLSL_ES_3_0:
{
kw << "vec" << N;
break;
@@ -53,6 +54,8 @@ std::string getVecKeyword(GpuLanguage lang)
kw << "half" << N;
break;
}
case GPU_LANGUAGE_MSL_2_0:
case GPU_LANGUAGE_HLSL_DX11:
{
kw << "float" << N;
@@ -85,6 +88,8 @@ void getTexDecl(GpuLanguage lang,
case GPU_LANGUAGE_GLSL_1_3:
case GPU_LANGUAGE_CG:
case GPU_LANGUAGE_GLSL_4_0:
case GPU_LANGUAGE_GLSL_ES_1_0:
case GPU_LANGUAGE_GLSL_ES_3_0:
{
textureDecl = "";
@@ -108,6 +113,17 @@ void getTexDecl(GpuLanguage lang,
{
throw Exception("Unsupported by the Open Shading language (OSL) translation.");
}
case GPU_LANGUAGE_MSL_2_0:
{
std::ostringstream t;
t << "texture" << N << "d<float> " << textureName << ";";
textureDecl = t.str();
t.str("");
t << "sampler" << " " << samplerName << ";";
samplerDecl = t.str();
break;
}
default:
{
@@ -132,6 +148,15 @@ std::string getTexSample(GpuLanguage lang,
kw << "texture" << N << "D(" << samplerName << ", " << coords << ")";
break;
}
case GPU_LANGUAGE_GLSL_ES_1_0:
{
if (N == 1) {
throw Exception("1D textures are unsupported by OpenGL ES.");
}
kw << "texture" << N << "D(" << samplerName << ", " << coords << ")";
break;
}
case GPU_LANGUAGE_CG:
{
kw << "tex" << N << "D(" << samplerName << ", " << coords << ")";
@@ -147,11 +172,25 @@ std::string getTexSample(GpuLanguage lang,
kw << "texture(" << samplerName << ", " << coords << ")";
break;
}
case GPU_LANGUAGE_GLSL_ES_3_0:
{
if (N == 1) {
throw Exception("1D textures are unsupported by OpenGL ES.");
}
kw << "texture(" << samplerName << ", " << coords << ")";
break;
}
case LANGUAGE_OSL_1:
{
throw Exception("Unsupported by the Open Shading language (OSL) translation.");
}
case GPU_LANGUAGE_MSL_2_0:
{
kw << textureName << ".sample(" << samplerName << ", " << coords << ")";
break;
}
default:
{
throw Exception("Unknown GPU shader language.");
@@ -285,12 +324,7 @@ void GpuShaderText::flushLine()
m_ossLine.clear();
}
std::string GpuShaderText::floatKeyword() const
{
return (m_lang == GPU_LANGUAGE_CG ? "half" : "float");
}
std::string GpuShaderText::floatKeywordConst() const
std::string GpuShaderText::constKeyword() const
{
std::string str;
@@ -299,7 +333,10 @@ std::string GpuShaderText::floatKeywordConst() const
case GPU_LANGUAGE_GLSL_1_2:
case GPU_LANGUAGE_GLSL_1_3:
case GPU_LANGUAGE_GLSL_4_0:
case GPU_LANGUAGE_GLSL_ES_1_0:
case GPU_LANGUAGE_GLSL_ES_3_0:
case GPU_LANGUAGE_HLSL_DX11:
case GPU_LANGUAGE_MSL_2_0:
{
str += "const";
str += " ";
@@ -310,6 +347,19 @@ std::string GpuShaderText::floatKeywordConst() const
break;
}
return str;
}
std::string GpuShaderText::floatKeyword() const
{
return (m_lang == GPU_LANGUAGE_CG ? "half" : "float");
}
std::string GpuShaderText::floatKeywordConst() const
{
std::string str;
str += constKeyword();
str += floatKeyword();
return str;
@@ -340,10 +390,20 @@ std::string GpuShaderText::colorDecl(const std::string & name) const
return (m_lang==LANGUAGE_OSL_1 ? "color" : float3Keyword()) + " " + name;
}
void GpuShaderText::declareVarConst(const std::string & name, float v)
{
newLine() << constKeyword() << declareVarStr(name, v) << ";";
}
void GpuShaderText::declareVar(const std::string & name, float v)
{
newLine() << declareVarStr(name, v) << ";";
}
// TODO: OSL: The method only solves the problem for constant float values. The code must also
// support the in-place declarations (like res = t + vec3(...) for example).
void GpuShaderText::declareVar(const std::string & name, float v)
std::string GpuShaderText::declareVarStr(const std::string & name, float v)
{
if (name.empty())
{
@@ -369,21 +429,47 @@ void GpuShaderText::declareVar(const std::string & name, float v)
oss.precision(std::numeric_limits<float>::max_digits10);
oss << newVal;
newLine() << floatDecl(name) << " = " << oss.str() << ";";
return;
return floatDecl(name) + " = " + oss.str();
}
newLine() << floatDecl(name) << " = " << getFloatString(v, m_lang) << ";";
return floatDecl(name) + " = " + getFloatString(v, m_lang);
}
std::string GpuShaderText::vectorCompareExpression(const std::string& lhs, const std::string& op, const std::string& rhs)
{
std::string ret = lhs + " " + op + " " + rhs;
if(m_lang == GPU_LANGUAGE_MSL_2_0)
{
ret = "any( " + ret + " )";
}
return ret;
}
void GpuShaderText::declareVarConst(const std::string & name, bool v)
{
newLine() << constKeyword() << declareVarStr(name, v) << ";";
}
void GpuShaderText::declareVar(const std::string & name, bool v)
{
newLine() << declareVarStr(name, v) << ";";
}
std::string GpuShaderText::declareVarStr(const std::string & name, bool v)
{
if (name.empty())
{
throw Exception("GPU variable name is empty.");
}
newLine() << "bool " << name << " = " << (v ? "true;" : "false;");
if (m_lang==LANGUAGE_OSL_1)
{
return intKeyword() + " " + name + " = " + (v ? "1" : "0");
}
else
{
return "bool " + name + " = " + (v ? "true" : "false");
}
}
void GpuShaderText::declareFloatArrayConst(const std::string & name, int size, const float * v)
@@ -404,6 +490,8 @@ void GpuShaderText::declareFloatArrayConst(const std::string & name, int size, c
case GPU_LANGUAGE_GLSL_1_2:
case GPU_LANGUAGE_GLSL_1_3:
case GPU_LANGUAGE_GLSL_4_0:
case GPU_LANGUAGE_GLSL_ES_1_0:
case GPU_LANGUAGE_GLSL_ES_3_0:
{
nl << floatKeywordConst() << " " << name << "[" << size << "] = ";
nl << floatKeyword() << "[" << size << "](";
@@ -421,6 +509,7 @@ void GpuShaderText::declareFloatArrayConst(const std::string & name, int size, c
case LANGUAGE_OSL_1:
case GPU_LANGUAGE_CG:
case GPU_LANGUAGE_HLSL_DX11:
case GPU_LANGUAGE_MSL_2_0:
{
nl << floatKeywordConst() << " " << name << "[" << size << "] = {";
for (int i = 0; i < size; ++i)
@@ -455,6 +544,8 @@ void GpuShaderText::declareIntArrayConst(const std::string & name, int size, con
case GPU_LANGUAGE_GLSL_1_2:
case GPU_LANGUAGE_GLSL_1_3:
case GPU_LANGUAGE_GLSL_4_0:
case GPU_LANGUAGE_GLSL_ES_1_0:
case GPU_LANGUAGE_GLSL_ES_3_0:
{
nl << "const " << intKeyword() << " " << name << "[" << size << "] = "
<< intKeyword() << "[" << size << "](";
@@ -470,6 +561,7 @@ void GpuShaderText::declareIntArrayConst(const std::string & name, int size, con
break;
}
case GPU_LANGUAGE_HLSL_DX11:
case GPU_LANGUAGE_MSL_2_0:
{
nl << "const " << intKeyword() << " " << name << "[" << size << "] = {";
for (int i = 0; i < size; ++i)
@@ -760,27 +852,27 @@ std::string GpuShaderText::sampleTex3D(const std::string& textureName,
void GpuShaderText::declareUniformFloat(const std::string & uniformName)
{
newLine() << "uniform " << floatKeyword() << " " << uniformName << ";";
newLine() << (m_lang == GPU_LANGUAGE_MSL_2_0 ? "" : "uniform ") << floatKeyword() << " " << uniformName << ";";
}
void GpuShaderText::declareUniformBool(const std::string & uniformName)
{
newLine() << "uniform bool " << uniformName << ";";
newLine() << (m_lang == GPU_LANGUAGE_MSL_2_0 ? "" : "uniform ") << "bool " << uniformName << ";";
}
void GpuShaderText::declareUniformFloat3(const std::string & uniformName)
{
newLine() << "uniform " << float3Keyword() << " " << uniformName << ";";
newLine() << (m_lang == GPU_LANGUAGE_MSL_2_0 ? "" : "uniform ") << float3Keyword() << " " << uniformName << ";";
}
void GpuShaderText::declareUniformArrayFloat(const std::string & uniformName, unsigned int size)
{
newLine() << "uniform " << floatKeyword() << " " << uniformName << "[" << size << "];";
newLine() << (m_lang == GPU_LANGUAGE_MSL_2_0 ? "" : "uniform ") << floatKeyword() << " " << uniformName << "[" << size << "];";
}
void GpuShaderText::declareUniformArrayInt(const std::string & uniformName, unsigned int size)
{
newLine() << "uniform " << intKeyword() << " " << uniformName << "[" << size << "];";
newLine() << (m_lang == GPU_LANGUAGE_MSL_2_0 ? "" : "uniform ") << intKeyword() << " " << uniformName << "[" << size << "];";
}
// Keep the method private as only float & double types are expected
@@ -798,6 +890,8 @@ std::string matrix4Mul(const T * m4x4, const std::string & vecName, GpuLanguage
case GPU_LANGUAGE_GLSL_1_2:
case GPU_LANGUAGE_GLSL_1_3:
case GPU_LANGUAGE_GLSL_4_0:
case GPU_LANGUAGE_GLSL_ES_1_0:
case GPU_LANGUAGE_GLSL_ES_3_0:
{
// OpenGL shader program requests a transposed matrix
kw << "mat4("
@@ -818,12 +912,12 @@ std::string matrix4Mul(const T * m4x4, const std::string & vecName, GpuLanguage
}
case LANGUAGE_OSL_1:
{
kw << vecName << " * matrix("
<< m4x4[ 0] << ", " << m4x4[ 1] << ", " << m4x4[ 2] << ", " << m4x4[ 3] << ", "
<< m4x4[ 4] << ", " << m4x4[ 5] << ", " << m4x4[ 6] << ", " << m4x4[ 7] << ", "
<< m4x4[ 8] << ", " << m4x4[ 9] << ", " << m4x4[10] << ", " << m4x4[11] << ", "
<< m4x4[12] << ", " << m4x4[13] << ", " << m4x4[14] << ", " << m4x4[15]
<< ")";
kw << "matrix(" << getMatrixValues<T, 4>(m4x4, lang, false) << ") * " << vecName;
break;
}
case GPU_LANGUAGE_MSL_2_0:
{
kw << "float4x4(" << getMatrixValues<T, 4>(m4x4, lang, true) << ") * " << vecName;
break;
}
@@ -858,6 +952,9 @@ std::string GpuShaderText::lerp(const std::string & x,
case GPU_LANGUAGE_GLSL_1_2:
case GPU_LANGUAGE_GLSL_1_3:
case GPU_LANGUAGE_GLSL_4_0:
case GPU_LANGUAGE_GLSL_ES_1_0:
case GPU_LANGUAGE_GLSL_ES_3_0:
case GPU_LANGUAGE_MSL_2_0:
{
kw << "mix(" << x << ", " << y << ", " << a << ")";
break;
@@ -886,12 +983,15 @@ std::string GpuShaderText::float3GreaterThan(const std::string & a,
case GPU_LANGUAGE_GLSL_1_2:
case GPU_LANGUAGE_GLSL_1_3:
case GPU_LANGUAGE_GLSL_4_0:
case GPU_LANGUAGE_GLSL_ES_1_0:
case GPU_LANGUAGE_GLSL_ES_3_0:
case GPU_LANGUAGE_CG:
{
kw << float3Keyword() << "(greaterThan( " << a << ", " << b << "))";
break;
}
case LANGUAGE_OSL_1:
case GPU_LANGUAGE_MSL_2_0:
case GPU_LANGUAGE_HLSL_DX11:
{
kw << float3Keyword() << "("
@@ -918,17 +1018,20 @@ std::string GpuShaderText::float4GreaterThan(const std::string & a,
case GPU_LANGUAGE_GLSL_1_2:
case GPU_LANGUAGE_GLSL_1_3:
case GPU_LANGUAGE_GLSL_4_0:
case GPU_LANGUAGE_GLSL_ES_1_0:
case GPU_LANGUAGE_GLSL_ES_3_0:
case GPU_LANGUAGE_CG:
{
kw << float4Keyword() << "(greaterThan( " << a << ", " << b << "))";
break;
}
case GPU_LANGUAGE_MSL_2_0:
case GPU_LANGUAGE_HLSL_DX11:
{
kw << float4Keyword() << "("
<< "(" << a << "[0] > " << b << "[0]) ? 1.0 : 0.0, "
<< "(" << a << "[1] > " << b << "[1]) ? 1.0 : 0.0, "
<< "(" << a << "[2] > " << b << "[2]) ? 1.0 : 0.0) "
<< "(" << a << "[2] > " << b << "[2]) ? 1.0 : 0.0, "
<< "(" << a << "[3] > " << b << "[3]) ? 1.0 : 0.0)";
break;
}
@@ -938,7 +1041,7 @@ std::string GpuShaderText::float4GreaterThan(const std::string & a,
<< "(" << a << ".rgb.r > " << b << ".x) ? 1.0 : 0.0, "
<< "(" << a << ".rgb.g > " << b << ".y) ? 1.0 : 0.0, "
<< "(" << a << ".rgb.b > " << b << ".z) ? 1.0 : 0.0, "
<< "(" << a << ".a > " << b << ".w) ? 1.0 : 0.0)";
<< "(" << a << ".a > " << b << ".w) ? 1.0 : 0.0)";
break;
}
@@ -960,18 +1063,25 @@ std::string GpuShaderText::atan2(const std::string & y,
case GPU_LANGUAGE_GLSL_1_2:
case GPU_LANGUAGE_GLSL_1_3:
case GPU_LANGUAGE_GLSL_4_0:
case GPU_LANGUAGE_GLSL_ES_1_0:
case GPU_LANGUAGE_GLSL_ES_3_0:
{
// note: "atan" not "atan2"
kw << "atan(" << y << ", " << x << ")";
break;
}
case LANGUAGE_OSL_1:
case GPU_LANGUAGE_HLSL_DX11:
{
// note: operand order is swapped in HLSL
kw << "atan2(" << x << ", " << y << ")";
break;
}
case LANGUAGE_OSL_1:
case GPU_LANGUAGE_MSL_2_0:
{
kw << "atan2(" << y << ", " << x << ")";
break;
}
default:
{
@@ -990,19 +1100,20 @@ std::string GpuShaderText::sign(const std::string & v) const
case GPU_LANGUAGE_GLSL_1_2:
case GPU_LANGUAGE_GLSL_1_3:
case GPU_LANGUAGE_GLSL_4_0:
case GPU_LANGUAGE_GLSL_ES_1_0:
case GPU_LANGUAGE_GLSL_ES_3_0:
case GPU_LANGUAGE_HLSL_DX11:
case GPU_LANGUAGE_MSL_2_0:
{
kw << "sign(" << v << ");";
break;
}
case LANGUAGE_OSL_1:
{
// The challenge is only to return a vector4 type instead of a color4.
kw << "sign(" << float4Const(v + ".rgb.r", v + ".rgb.g",
v + ".rgb.b", v + ".a") << ");";
break;
}
default:
{
throw Exception("Unknown GPU shader language.");
@@ -1073,4 +1184,3 @@ void AddLogToLinShader(GpuShaderCreatorRcPtr & shaderCreator, GpuShaderText & st
}
} // namespace OCIO_NAMESPACE
+11 -6
View File
@@ -67,6 +67,8 @@ public:
// Basic types.
//
std::string constKeyword() const;
std::string floatKeyword() const;
std::string floatKeywordConst() const;
std::string floatDecl(const std::string& name) const;
@@ -74,16 +76,22 @@ public:
std::string intKeyword() const;
std::string colorDecl(const std::string& name) const;
std::string vectorCompareExpression(const std::string& lhs, const std::string& op, const std::string& rhs);
//
// Scalar & arrays helper functions.
//
// Declare a float variable.
std::string declareVarStr(const std::string & name, float v);
void declareVar(const std::string & name, float v);
void declareVarConst(const std::string & name, float v);
// Declare a bool variable.
std::string declareVarStr(const std::string & name, bool v);
void declareVar(const std::string & name, bool v);
void declareVarConst(const std::string & name, bool v);
// Declare a float array variable.
void declareFloatArrayConst(const std::string & name, int size, const float * v);
@@ -108,8 +116,7 @@ public:
std::string float3Const(float x, float y, float z) const;
std::string float3Const(double x, double y, double z) const;
// Get the string for creating constant vector with three elements
std::string float3Const(const std::string& x, const std::string& y,
const std::string& z) const;
std::string float3Const(const std::string& x, const std::string& y, const std::string& z) const;
// Get the string for creating constant vector with three elements
std::string float3Const(float v) const;
std::string float3Const(double v) const;
@@ -119,11 +126,9 @@ public:
std::string float3Decl(const std::string& name) const;
// Declare and initialize a vector with three elements
void declareFloat3(const std::string& name,
float x, float y, float z);
void declareFloat3(const std::string& name, float x, float y, float z);
void declareFloat3(const std::string& name, const Float3 & vec3);
void declareFloat3(const std::string& name,
double x, double y, double z);
void declareFloat3(const std::string& name, double x, double y, double z);
// Declare and initialize a vector with three elements
void declareFloat3(const std::string& name,
const std::string& x, const std::string& y, const std::string& z);
-9
View File
@@ -54,9 +54,6 @@ OpData & OpData::operator=(const OpData & rhs)
return *this;
}
OpData::~OpData()
{ }
OpDataRcPtr OpData::getIdentityReplacement() const
{
return std::make_shared<MatrixOpData>();
@@ -131,12 +128,6 @@ const char * GetTypeName(OpData::Type type)
throw Exception("Unexpected op type.");
}
Op::Op()
{ }
Op::~Op()
{ }
bool Op::canCombineWith(ConstOpRcPtr & /*op*/) const
{
return false;
+15 -7
View File
@@ -34,8 +34,12 @@ typedef std::vector<ConstOpCPURcPtr> ConstOpCPURcPtrVec;
class OpCPU
{
public:
OpCPU() {}
virtual ~OpCPU() {}
OpCPU() = default;
OpCPU(const OpCPU &) = delete;
OpCPU(OpCPU &&) = delete;
OpCPU & operator=(const OpCPU &) = delete;
OpCPU & operator=(OpCPU &&) = delete;
virtual ~OpCPU() = default;
// All the Ops assume float pointers (i.e. always float bit depths) except
// the 1D LUT CPU Op where the finalization depends on input and output bit depths.
@@ -114,8 +118,10 @@ public:
public:
OpData();
OpData(const OpData & rhs);
OpData(OpData && rhs) = delete;
OpData & operator=(const OpData & rhs);
virtual ~OpData();
OpData & operator=(OpData && rhs) = delete;
virtual ~OpData() = default;
const std::string & getID() const;
void setID(const std::string & id);
@@ -168,7 +174,11 @@ const char * GetTypeName(OpData::Type type);
class Op
{
public:
virtual ~Op();
Op(const Op & rhs) = delete;
Op(Op && rhs) = delete;
Op & operator=(const Op & rhs) = delete;
Op & operator=(Op && rhs) = delete;
virtual ~Op() = default;
virtual OpRcPtr clone() const = 0;
@@ -270,12 +280,10 @@ public:
ConstOpDataRcPtr data() const { return std::const_pointer_cast<const OpData>(m_data); }
protected:
Op();
Op() = default;
OpDataRcPtr & data() { return m_data; }
private:
Op(const Op &) = delete;
Op& operator= (const Op &) = delete;
// The OpData instance holds the parameters (LUT values, matrix coefs, etc.) being used.
OpDataRcPtr m_data;
+31 -17
View File
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenColorIO Project.
#include <cmath>
#include <cstring>
#include <iostream>
#include <set>
@@ -11,6 +12,7 @@
#include "ParseUtils.h"
#include "Platform.h"
#include "utils/StringUtils.h"
#include "utils/NumberUtils.h"
namespace OCIO_NAMESPACE
@@ -257,12 +259,15 @@ const char * GpuLanguageToString(GpuLanguage language)
{
switch(language)
{
case GPU_LANGUAGE_CG: return "cg";
case GPU_LANGUAGE_GLSL_1_2: return "glsl_1.2";
case GPU_LANGUAGE_GLSL_1_3: return "glsl_1.3";
case GPU_LANGUAGE_GLSL_4_0: return "glsl_4.0";
case GPU_LANGUAGE_HLSL_DX11: return "hlsl_dx11";
case LANGUAGE_OSL_1: return "osl_1";
case GPU_LANGUAGE_CG: return "cg";
case GPU_LANGUAGE_GLSL_1_2: return "glsl_1.2";
case GPU_LANGUAGE_GLSL_1_3: return "glsl_1.3";
case GPU_LANGUAGE_GLSL_4_0: return "glsl_4.0";
case GPU_LANGUAGE_GLSL_ES_1_0: return "glsl_es_1.0";
case GPU_LANGUAGE_GLSL_ES_3_0: return "glsl_es_3.0";
case GPU_LANGUAGE_HLSL_DX11: return "hlsl_dx11";
case GPU_LANGUAGE_MSL_2_0: return "msl_2";
case LANGUAGE_OSL_1: return "osl_1";
}
throw Exception("Unsupported GPU shader language.");
@@ -274,11 +279,14 @@ GpuLanguage GpuLanguageFromString(const char * s)
const std::string str = StringUtils::Lower(p);
if(str == "cg") return GPU_LANGUAGE_CG;
else if(str == "glsl_1.2") return GPU_LANGUAGE_GLSL_1_2;
else if(str == "glsl_1.3") return GPU_LANGUAGE_GLSL_1_3;
else if(str == "glsl_4.0") return GPU_LANGUAGE_GLSL_4_0;
else if(str == "hlsl_dx11") return GPU_LANGUAGE_HLSL_DX11;
else if(str == "osl_1") return LANGUAGE_OSL_1;
else if(str == "glsl_1.2") return GPU_LANGUAGE_GLSL_1_2;
else if(str == "glsl_1.3") return GPU_LANGUAGE_GLSL_1_3;
else if(str == "glsl_4.0") return GPU_LANGUAGE_GLSL_4_0;
else if(str == "glsl_es_1.0") return GPU_LANGUAGE_GLSL_ES_1_0;
else if(str == "glsl_es_3.0") return GPU_LANGUAGE_GLSL_ES_3_0;
else if(str == "hlsl_dx11") return GPU_LANGUAGE_HLSL_DX11;
else if(str == "osl_1") return LANGUAGE_OSL_1;
else if(str == "msl_2") return GPU_LANGUAGE_MSL_2_0;
std::ostringstream oss;
oss << "Unsupported GPU shader language: '" << p << "'.";
@@ -520,6 +528,7 @@ static constexpr int DOUBLE_DECIMALS = 16;
std::string FloatToString(float value)
{
std::ostringstream pretty;
pretty.imbue(std::locale::classic());
pretty.precision(FLOAT_DECIMALS);
pretty << value;
return pretty.str();
@@ -530,6 +539,7 @@ std::string FloatVecToString(const float * fval, unsigned int size)
if(size<=0) return "";
std::ostringstream pretty;
pretty.imbue(std::locale::classic());
pretty.precision(FLOAT_DECIMALS);
for(unsigned int i=0; i<size; ++i)
{
@@ -544,9 +554,9 @@ bool StringToFloat(float * fval, const char * str)
{
if(!str) return false;
std::istringstream inputStringstream(str);
float x;
if(!(inputStringstream >> x))
float x = NAN;
const auto result = NumberUtils::from_chars(str, str + strlen(str), x);
if (result.ec != std::errc())
{
return false;
}
@@ -561,6 +571,7 @@ bool StringToInt(int * ival, const char * str, bool failIfLeftoverChars)
if(!ival) return false;
std::istringstream i(str);
i.imbue(std::locale::classic());
char c=0;
if (!(i >> *ival) || (failIfLeftoverChars && i.get(c))) return false;
return true;
@@ -569,6 +580,7 @@ bool StringToInt(int * ival, const char * str, bool failIfLeftoverChars)
std::string DoubleToString(double value)
{
std::ostringstream pretty;
pretty.imbue(std::locale::classic());
pretty.precision(DOUBLE_DECIMALS);
pretty << value;
return pretty.str();
@@ -579,6 +591,7 @@ std::string DoubleVecToString(const double * val, unsigned int size)
if (size <= 0) return "";
std::ostringstream pretty;
pretty.imbue(std::locale::classic());
pretty.precision(DOUBLE_DECIMALS);
for (unsigned int i = 0; i<size; ++i)
{
@@ -595,9 +608,10 @@ bool StringVecToFloatVec(std::vector<float> &floatArray, const StringUtils::Stri
for(unsigned int i=0; i<lineParts.size(); i++)
{
std::istringstream inputStringstream(lineParts[i]);
float x;
if(!(inputStringstream >> x))
float x = NAN;
const char *str = lineParts[i].c_str();
const auto result = NumberUtils::from_chars(str, str + lineParts[i].size(), x);
if (result.ec != std::errc())
{
return false;
}
+3 -33
View File
@@ -4,12 +4,12 @@
#include <iostream>
#include <map>
#include <sys/stat.h>
#include <OpenColorIO/OpenColorIO.h>
#include "Mutex.h"
#include "PathUtils.h"
#include "Platform.h"
#include "pystring/pystring.h"
#include "utils/StringUtils.h"
@@ -26,39 +26,9 @@ namespace OCIO_NAMESPACE
{
namespace
{
// Here is the explanation of the stat() method:
// https://pubs.opengroup.org/onlinepubs/009695299/basedefs/sys/stat.h.html
// "The st_ino and st_dev fields taken together uniquely identify the file within the system."
//
// However there are limitations to the stat() support on some Windows file systems:
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions?redirectedfrom=MSDN&view=vs-2019
// "The inode, and therefore st_ino, has no meaning in the FAT, HPFS, or NTFS file systems."
// That's the default hash method implementation to compute a hash key based on a file content.
std::string DefaultComputeHash(const std::string &filename)
{
struct stat fileInfo;
if (stat(filename.c_str(), &fileInfo) == 0)
{
// Treat the st_dev (i.e. device) + st_ino (i.e. inode) as a proxy for the contents.
std::ostringstream fasthash;
fasthash << fileInfo.st_dev << ":";
#ifdef _WIN32
// TODO: The hard-linked files are then not correctly supported on Windows platforms.
fasthash << std::hash<std::string>{}(filename);
#else
fasthash << fileInfo.st_ino;
#endif
return fasthash.str();
}
return "";
}
// The global variable holds the hash function to use.
// It could be changed using SetComputeHashFunction() to customize the implementation.
ComputeHashFunction g_hashFunction = DefaultComputeHash;
ComputeHashFunction g_hashFunction = Platform::CreateFileContentHash;
// We mutex both the main map and each item individually, so that
// the potentially slow stat calls dont block other lookups to already
@@ -86,7 +56,7 @@ void SetComputeHashFunction(ComputeHashFunction hashFunction)
void ResetComputeHashFunction()
{
g_hashFunction = DefaultComputeHash;
g_hashFunction = Platform::CreateFileContentHash;
}
std::string GetFastFileHash(const std::string & filename)
+138 -6
View File
@@ -1,8 +1,11 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenColorIO Project.
#include <codecvt>
#include <locale>
#include <random>
#include <sstream>
#include <sys/stat.h>
#include <vector>
#include <OpenColorIO/OpenColorIO.h>
@@ -49,12 +52,36 @@ bool Getenv(const char * name, std::string & value)
return false;
}
#ifdef _WIN32
if(uint32_t size = GetEnvironmentVariable(name, nullptr, 0))
#if defined(_WIN32)
// Define working strings, converting to UTF-16 if necessary
#ifdef UNICODE
std::wstring name_str = Utf8ToUtf16(name);
std::wstring value_str;
#else
std::string name_str = name;
std::string value_str;
#endif
if(uint32_t size = GetEnvironmentVariable(name_str.c_str(), nullptr, 0))
{
std::vector<char> buffer(size);
GetEnvironmentVariable(name, buffer.data(), size);
value = std::string(buffer.data());
value_str.resize(size);
GetEnvironmentVariable(name_str.c_str(), &value_str[0], size);
// GetEnvironmentVariable is designed for raw pointer strings and therefore requires that
// the destination buffer be long enough to place a null terminator at the end of it. Since
// we're using std::wstrings here, the null terminator is unnecessary (and causes false
// negatives in unit tests since the extra character makes it "non-equal" to normally
// defined std::wstrings). Therefore, we pop the last character off (the null terminator)
// to ensure that the string conforms to expectations.
value_str.pop_back();
// Return value, converting to UTF-8 if necessary
#ifdef UNICODE
value = Utf16ToUtf8(value_str);
#else
value = value_str;
#endif
return true;
}
else
@@ -81,7 +108,13 @@ void Setenv(const char * name, const std::string & value)
// exists. To avoid the ambiguity, use Unsetenv() when the env. variable removal if needed.
#ifdef _WIN32
#ifdef UNICODE
_wputenv_s(Utf8ToUtf16(name).c_str(), Utf8ToUtf16(value).c_str());
#else
_putenv_s(name, value.c_str());
#endif
#else
::setenv(name, value.c_str(), 1);
#endif
@@ -95,8 +128,14 @@ void Unsetenv(const char * name)
}
#ifdef _WIN32
#ifdef UNICODE
// Note that the Windows _putenv_s() removes the env. variable if the value is empty.
_wputenv_s(Utf8ToUtf16(name).c_str(), L"");
#else
_putenv_s(name, "");
#endif
#else
::unsetenv(name);
#endif
@@ -174,13 +213,21 @@ std::string CreateTempFilename(const std::string & filenameExt)
// Note: Because of security issue, tmpnam could not be used.
// Note 2: MinGW doesn't define L_tmpnam_s, we need to patch it in.
// https://www.mail-archive.com/mingw-w64-public@lists.sourceforge.net/msg17360.html
#if !defined(L_tmpnam_s)
#define L_tmpnam_s L_tmpnam
#endif
char tmpFilename[L_tmpnam_s];
if(tmpnam_s(tmpFilename))
{
throw Exception("Could not create a temporary file.");
}
filename = tmpFilename;
// Note that when a file name is pre-pended with a backslash and no path information, such as \fname21, this
// indicates that the name is valid for the current working directory.
filename = tmpFilename[0] == '\\' ? tmpFilename + 1 : tmpFilename;
#else
@@ -197,6 +244,91 @@ std::string CreateTempFilename(const std::string & filenameExt)
return filename;
}
std::ifstream CreateInputFileStream(const char * filename, std::ios_base::openmode mode)
{
#if defined(_WIN32) && defined(UNICODE)
return std::ifstream(Utf8ToUtf16(filename).c_str(), mode);
#else
return std::ifstream(filename, mode);
#endif
}
void OpenInputFileStream(std::ifstream & stream, const char * filename, std::ios_base::openmode mode)
{
#if defined(_WIN32) && defined(UNICODE)
stream.open(Utf8ToUtf16(filename).c_str(), mode);
#else
stream.open(filename, mode);
#endif
}
std::wstring Utf8ToUtf16(const std::string & str)
{
if (str.empty()) {
return std::wstring();
}
#ifdef _WIN32
int sz = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
std::wstring wstr(sz, 0);
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstr[0], sz);
return wstr;
#else
throw Exception("Only supported by the Windows platform.");
#endif
}
std::string Utf16ToUtf8(const std::wstring & wstr)
{
if (wstr.empty()) {
return std::string();
}
#ifdef _WIN32
int sz = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
std::string str(sz, 0);
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &str[0], sz, NULL, NULL);
return str;
#else
throw Exception("Only supported by the Windows platform.");
#endif
}
// Here is the explanation of the stat() method:
// https://pubs.opengroup.org/onlinepubs/009695299/basedefs/sys/stat.h.html
// "The st_ino and st_dev fields taken together uniquely identify the file within the system."
//
// However there are limitations to the stat() support on some Windows file systems:
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions?redirectedfrom=MSDN&view=vs-2019
// "The inode, and therefore st_ino, has no meaning in the FAT, HPFS, or NTFS file systems."
// That's the default hash method implementation to compute a hash key based on a file content.
std::string CreateFileContentHash(const std::string &filename)
{
#if defined(_WIN32) && defined(UNICODE)
struct _stat fileInfo;
if (_wstat(Platform::Utf8ToUtf16(filename).c_str(), &fileInfo) == 0)
#else
struct stat fileInfo;
if (stat(filename.c_str(), &fileInfo) == 0)
#endif
{
// Treat the st_dev (i.e. device) + st_ino (i.e. inode) as a proxy for the contents.
std::ostringstream fasthash;
fasthash << fileInfo.st_dev << ":";
#ifdef _WIN32
// TODO: The hard-linked files are then not correctly supported on Windows platforms.
fasthash << std::hash<std::string>{}(filename);
#else
fasthash << fileInfo.st_ino;
#endif
return fasthash.str();
}
return "";
}
} // Platform
+31
View File
@@ -20,6 +20,7 @@
#endif // _WIN32
#include <fstream>
#include <string>
@@ -28,6 +29,20 @@
#define sscanf sscanf_s
// Define std::tstring as a wstring when Unicode is enabled and a regular string otherwise
namespace std
{
#ifdef _UNICODE
typedef wstring tstring;
typedef wostringstream tostringstream;
#define LogDebugT(x) LogDebug(Platform::Utf16ToUtf8(x))
#else
typedef string tstring;
typedef ostringstream tostringstream;
#define LogDebugT(x) LogDebug(x)
#endif
}
#endif // _WIN32
@@ -71,8 +86,24 @@ void AlignedFree(void * memBlock);
// Note: Temporary files should be at some point deleted by the OS (depending of the OS
// and various platform specific settings). To be safe, add some code to remove
// the file if created.
// FIXME: Implement a function or class for temporary file creation useable by all tests.
std::string CreateTempFilename(const std::string & filenameExt);
// Create an input file stream (std::ifstream) using a UTF-8 filename on any platform.
std::ifstream CreateInputFileStream(const char * filename, std::ios_base::openmode mode);
// Open an input file stream (std::ifstream) using a UTF-8 filename on any platform.
void OpenInputFileStream(std::ifstream & stream, const char * filename, std::ios_base::openmode mode);
// Create a unique hash of a file provided as a UTF-8 filename on any platform.
std::string CreateFileContentHash(const std::string &filename);
// Convert UTF-8 string to UTF-16LE.
std::wstring Utf8ToUtf16(const std::string & str);
// Convert UTF-16LE string to UTF-8.
std::string Utf16ToUtf8(const std::wstring & str);
}
} // namespace OCIO_NAMESPACE
+17 -11
View File
@@ -12,6 +12,8 @@
#include <Logging.h>
#include "Platform.h"
namespace OCIO_NAMESPACE
{
@@ -33,7 +35,7 @@ void SystemMonitorsImpl::getAllMonitors()
DWORD dispNum = 0;
while (EnumDisplayDevices(nullptr, dispNum, &dispDevice, 0))
{
const std::string deviceName = dispDevice.DeviceName;
const std::tstring deviceName = dispDevice.DeviceName;
// Only select active monitors.
if ((dispDevice.StateFlags & DISPLAY_DEVICE_ACTIVE)
@@ -49,37 +51,41 @@ void SystemMonitorsImpl::getAllMonitors()
// monitor name for that device.
EnumDisplayDevices(deviceName.c_str(), dispNum, &dispDevice, 0);
char icmPath[MAX_PATH + 1];
TCHAR icmPath[MAX_PATH + 1];
DWORD pathLength = MAX_PATH;
// TODO: Is a monitor without ICM profile possible?
// TODO: Several ICM profiles could be associated to a single device.
const std::string displayName
= deviceName + ", " + dispDevice.DeviceString;
const std::tstring displayName
= deviceName + TEXT(", ") + dispDevice.DeviceString;
// Get the associated ICM profile path.
if (GetICMProfile(hDC, &pathLength, icmPath))
{
#ifdef _UNICODE
m_monitors.push_back({Platform::Utf16ToUtf8(displayName), Platform::Utf16ToUtf8(icmPath)});
#else
m_monitors.push_back({displayName, icmPath});
#endif
}
else
{
std::ostringstream oss;
oss << "Unable to access the ICM profile for the monitor '"
<< displayName << "'.";
std::tostringstream oss;
oss << TEXT("Unable to access the ICM profile for the monitor '")
<< displayName << TEXT("'.");
LogDebug(oss.str());
LogDebugT(oss.str());
}
DeleteDC(hDC);
}
else
{
std::ostringstream oss;
oss << "Unable to access the monitor '" << deviceName << "'.";
LogDebug(oss.str());
std::tostringstream oss;
oss << TEXT("Unable to access the monitor '") << deviceName << TEXT("'.");
LogDebugT(oss.str());
}
}
@@ -37,6 +37,7 @@
#include "ParseUtils.h"
#include "transforms/FileTransform.h"
#include "utils/StringUtils.h"
#include "utils/NumberUtils.h"
namespace OCIO_NAMESPACE
@@ -182,16 +183,11 @@ readLuts(std::istream& istream,
}
else if(inlut)
{
// StringToFloat was far slower, for 787456 values:
// - StringToFloat took 3879 (avg nanoseconds per value)
// - stdtod took 169 nanoseconds
char* endptr = 0;
float v = static_cast<float>(strtod(word.c_str(), &endptr));
float v{};
const auto result = NumberUtils::from_chars(word.c_str(), word.c_str() + word.size(), v);
if(!*endptr)
if (result.ec == std::errc())
{
// Since each word should contain a single
// float value, the pointer should be null
lutValues[lutname].push_back(v);
}
else
@@ -541,7 +541,7 @@ FileFormat * CreateFileFormatICC()
std::string GetProfileDescriptionFromICCProfile(const char * ICCProfileFilepath)
{
std::ifstream filestream(ICCProfileFilepath, std::ios_base::binary);
std::ifstream filestream = Platform::CreateInputFileStream(ICCProfileFilepath, std::ios_base::binary);
if (!filestream.good())
{
std::ostringstream os;
@@ -16,6 +16,7 @@
#include "pystring/pystring.h"
#include "transforms/FileTransform.h"
#include "utils/StringUtils.h"
#include "utils/NumberUtils.h"
/*
@@ -416,19 +417,18 @@ private:
std::string size_raw = std::string(s, len);
std::string size_clean = pystring::strip(size_raw, "'\" "); // strip quotes and space
char* endptr = 0;
int size_3d = static_cast<int>(strtol(size_clean.c_str(), &endptr, 10));
long int size_3d{};
const auto result = NumberUtils::from_chars(size_clean.c_str(), size_clean.c_str() + size_clean.size(), size_3d);
if (*endptr)
if (result.ec != std::errc())
{
// strtol didn't consume entire string, there was
// remaining data, thus did not contain a single integer
std::ostringstream os;
os << "Invalid LUT size value: '" << size_raw;
os << "'. Expected quoted integer";
pImpl->Throw(os.str().c_str());
}
pImpl->m_lutSize = size_3d;
pImpl->m_lutSize = static_cast<int>(size_3d);
}
else if (pImpl->m_data)
{
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenColorIO Project.
#include <cmath>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <OpenColorIO/OpenColorIO.h>
@@ -13,7 +15,7 @@
#include "Platform.h"
#include "transforms/FileTransform.h"
#include "utils/StringUtils.h"
#include "utils/NumberUtils.h"
/*
Version 1
@@ -124,10 +126,26 @@ CachedFileRcPtr LocalFileFormat::read(std::istream & istream,
}
else if(StringUtils::StartsWith(headerLine, "From"))
{
if (sscanf(lineBuffer, "From %f %f", &from_min, &from_max) != 2)
char fromMinS[64] = "";
char fromMaxS[64] = "";
#ifdef _WIN32
if (sscanf_s(lineBuffer, "From %s %s", fromMinS, 64, fromMaxS, 64) != 2)
#else
if (sscanf(lineBuffer, "From %s %s", fromMinS, fromMaxS) != 2)
#endif
{
ThrowErrorMessage("Invalid 'From' Tag", currentLine, headerLine);
}
else
{
const auto fromMinAnswer = NumberUtils::from_chars(fromMinS, fromMinS + 64, from_min);
const auto fromMaxAnswer = NumberUtils::from_chars(fromMaxS, fromMaxS + 64, from_max);
if (fromMinAnswer.ec != std::errc() || fromMaxAnswer.ec != std::errc())
{
ThrowErrorMessage("Invalid 'From' Tag", currentLine, headerLine);
}
}
}
else if(StringUtils::StartsWith(headerLine, "Components"))
{
@@ -179,7 +197,6 @@ CachedFileRcPtr LocalFileFormat::read(std::istream & istream,
int lineCount=0;
StringUtils::StringVec inputLUT;
std::vector<float> values;
while (istream.good())
@@ -192,10 +209,17 @@ CachedFileRcPtr LocalFileFormat::read(std::istream & istream,
if (line.length() != 0)
{
inputLUT = StringUtils::SplitByWhiteSpaces(StringUtils::Trim(lineBuffer));
values.clear();
if (!StringVecToFloatVec(values, inputLUT)
|| components != (int)values.size())
char inputLUT[4][64] = {"", "", "", ""};
#ifdef _WIN32
if (sscanf_s(lineBuffer, "%s %s %s %63s", inputLUT[0], 64,
inputLUT[1], 64, inputLUT[2], 64, inputLUT[3],
64) != components)
#else
if (sscanf(lineBuffer, "%s %s %s %63s", inputLUT[0],
inputLUT[1], inputLUT[2], inputLUT[3]) != components)
#endif
{
std::ostringstream os;
os << "Malformed LUT line. Expecting a ";
@@ -209,6 +233,26 @@ CachedFileRcPtr LocalFileFormat::read(std::istream & istream,
ThrowErrorMessage("Too many entries found", currentLine, "");
}
values.resize(components);
for (int i = 0; i < components; i++)
{
float v = NAN;
const auto result = NumberUtils::from_chars(inputLUT[i], inputLUT[i] + 64, v);
if (result.ec != std::errc())
{
std::ostringstream os;
os << "Malformed LUT line. Could not convert component";
os << i << " to a floating point number.";
ThrowErrorMessage("Malformed LUT line", currentLine,
line);
}
values[i] = v;
}
// If 1 component is specified, use x1 x1 x1.
if (components == 1)
{
@@ -12,6 +12,7 @@
#include "Platform.h"
#include "transforms/FileTransform.h"
#include "utils/StringUtils.h"
#include "utils/NumberUtils.h"
/*
@@ -131,7 +132,7 @@ CachedFileRcPtr LocalFileFormat::read(std::istream & istream,
// Parse table
int index = 0;
int rIndex, gIndex, bIndex;
float redValue, greenValue, blueValue;
float redValue = NAN, greenValue = NAN, blueValue = NAN;
int entriesRemaining = rSize * gSize * bSize;
Array & lutArray = lut3d->getArray();
@@ -141,10 +142,42 @@ CachedFileRcPtr LocalFileFormat::read(std::istream & istream,
{
istream.getline(lineBuffer, MAX_LINE_SIZE);
if (sscanf(lineBuffer, "%d %d %d %f %f %f",
char redValueS[64] = "";
char greenValueS[64] = "";
char blueValueS[64] = "";
#ifdef _WIN32
if (sscanf(lineBuffer,
"%d %d %d %s %s %s",
&rIndex, &gIndex, &bIndex,
&redValue, &greenValue, &blueValue) == 6)
redValueS, 64,
greenValueS, 64,
blueValueS, 64) == 6)
#else
if (sscanf(lineBuffer, "%d %d %d %s %s %s",
&rIndex, &gIndex, &bIndex,
redValueS, greenValueS, blueValueS) == 6)
#endif
{
const auto redValueAnswer = NumberUtils::from_chars(redValueS, redValueS + 64, redValue);
const auto greenValueAnswer = NumberUtils::from_chars(greenValueS, greenValueS + 64, greenValue);
const auto blueValueAnswer = NumberUtils::from_chars(blueValueS, blueValueS + 64, blueValue);
if (redValueAnswer.ec != std::errc()
|| greenValueAnswer.ec != std::errc()
|| blueValueAnswer.ec != std::errc())
{
std::ostringstream os;
os << "Error parsing .spi3d file (";
os << fileName;
os << "). ";
os << "Data is invalid. ";
os << "A color value is specified (";
os << redValueS << " " << greenValueS << " " << blueValueS;
os << ") that cannot be parsed as a floating-point triplet.";
throw Exception(os.str().c_str());
}
bool invalidIndex = false;
if (rIndex < 0 || rIndex >= rSize
|| gIndex < 0 || gIndex >= gSize
@@ -851,17 +851,17 @@ void CDLWriter::writeContent() const
oss.str("");
params = m_cdl->getSlopeParams();
oss << params[0] << ", " << params[1] << ", " << params[2];
oss << params[0] << " " << params[1] << " " << params[2];
m_formatter.writeContentTag(TAG_SLOPE, oss.str());
oss.str("");
params = m_cdl->getOffsetParams();
oss << params[0] << ", " << params[1] << ", " << params[2];
oss << params[0] << " " << params[1] << " " << params[2];
m_formatter.writeContentTag(TAG_OFFSET, oss.str());
oss.str("");
params = m_cdl->getPowerParams();
oss << params[0] << ", " << params[1] << ", " << params[2];
oss << params[0] << " " << params[1] << " " << params[2];
m_formatter.writeContentTag(TAG_POWER, oss.str());
}
m_formatter.writeEndTag(TAG_SOPNODE);
@@ -13,6 +13,8 @@
#include <OpenColorIO/OpenColorIO.h>
#include "MathUtils.h"
#include "utils/StringUtils.h"
#include "utils/NumberUtils.h"
#include "Platform.h"
@@ -156,16 +158,17 @@ void ParseNumber(const char * str, size_t startPos, size_t endPos, T & value)
const char * startParse = str + startPos;
double val = 0.0f;
char * endParse = nullptr;
// The strtod expects a C string and str might not be null terminated.
// However since strtod will stop parsing when it encounters characters
// that it cannot convert to a number, in practice it does not need to
// be null terminated.
// C++11 version of strtod processes NAN & INF ASCII values.
val = strtod(startParse, &endParse);
size_t adjustedStartPos = startPos;
size_t adjustedEndPos = endPos;
FindSubString(startParse, endPos - startPos, adjustedStartPos, adjustedEndPos);
const auto result = NumberUtils::from_chars(startParse + adjustedStartPos, startParse + adjustedEndPos, val);
value = (T)val;
if (endParse == startParse)
if (result.ec == std::errc::invalid_argument)
{
std::string fullStr(str, endPos);
std::string parsedStr(startParse, endPos - startPos);
@@ -187,10 +190,10 @@ void ParseNumber(const char * str, size_t startPos, size_t endPos, T & value)
<< TruncateString(fullStr.c_str(), endPos, 100) << "'.";
throw Exception(oss.str().c_str());
}
else if (endParse != str + endPos)
else if (result.ptr != str + endPos)
{
// Number is followed by something.
std::string fullStr(str, startPos + (endParse - startParse));
std::string fullStr(str, endPos);
std::string parsedStr(startParse, endPos - startPos);
std::ostringstream oss;
oss << "ParserNumber: '"
+13 -4
View File
@@ -265,14 +265,23 @@ void ExponentOp::extractGpuShaderInfo(GpuShaderCreatorRcPtr & shaderCreator) con
// outColor = pow(max(outColor, 0.), exp);
const std::string pxl(shaderCreator->getPixelName());
ss.newLine() << ss.float4Decl("res")
<< " = " << ss.float4Const(pxl + ".rgb.r",
pxl + ".rgb.g",
pxl + ".rgb.b",
pxl + ".a") << ";";
ss.newLine()
<< shaderCreator->getPixelName()
<< " = pow( "
<< "max( " << shaderCreator->getPixelName()
<< ", " << ss.float4Const(0.0f) << " )"
<< "res = pow( "
<< "max( res, " << ss.float4Const(0.0f) << " )"
<< ", " << ss.float4Const(expData()->m_exp4[0], expData()->m_exp4[1],
expData()->m_exp4[2], expData()->m_exp4[3]) << " );";
ss.newLine() << pxl << ".rgb = " << ss.float3Const("res.x", "res.y", "res.z") << ";";
ss.newLine() << pxl << ".a = res.w;";
ss.dedent();
ss.newLine() << "}";
@@ -18,8 +18,6 @@ class Renderer_ACES_RedMod03_Fwd : public OpCPU
{
public:
Renderer_ACES_RedMod03_Fwd() = delete;
Renderer_ACES_RedMod03_Fwd(const Renderer_ACES_RedMod03_Fwd &) = delete;
explicit Renderer_ACES_RedMod03_Fwd(ConstFixedFunctionOpDataRcPtr & data);
void apply(const void * inImg, void * outImg, long numPixels) const override;
@@ -29,7 +27,7 @@ protected:
float m_pivot;
float m_inv_width;
const float m_noiseLimit = 1e-2f;
static constexpr float m_noiseLimit = 1e-2f;
};
class Renderer_ACES_RedMod03_Inv : public Renderer_ACES_RedMod03_Fwd
@@ -44,8 +42,6 @@ class Renderer_ACES_RedMod10_Fwd : public OpCPU
{
public:
Renderer_ACES_RedMod10_Fwd() = delete;
Renderer_ACES_RedMod10_Fwd(const Renderer_ACES_RedMod03_Fwd &) = delete;
explicit Renderer_ACES_RedMod10_Fwd(ConstFixedFunctionOpDataRcPtr & data);
void apply(const void * inImg, void * outImg, long numPixels) const override;
@@ -55,7 +51,7 @@ protected:
float m_pivot;
float m_inv_width;
const float m_noiseLimit = 1e-2f;
static constexpr float m_noiseLimit = 1e-2f;
};
class Renderer_ACES_RedMod10_Inv : public Renderer_ACES_RedMod10_Fwd
@@ -70,24 +66,20 @@ class Renderer_ACES_Glow03_Fwd : public OpCPU
{
public:
Renderer_ACES_Glow03_Fwd() = delete;
Renderer_ACES_Glow03_Fwd(const Renderer_ACES_Glow03_Fwd &) = delete;
Renderer_ACES_Glow03_Fwd(ConstFixedFunctionOpDataRcPtr & data,
float glowGain, float glowMid);
Renderer_ACES_Glow03_Fwd(ConstFixedFunctionOpDataRcPtr & data, float glowGain, float glowMid);
void apply(const void * inImg, void * outImg, long numPixels) const override;
protected:
float m_glowGain, m_glowMid;
const float m_noiseLimit = 1e-2f;
static constexpr float m_noiseLimit = 1e-2f;
};
class Renderer_ACES_Glow03_Inv : public Renderer_ACES_Glow03_Fwd
{
public:
Renderer_ACES_Glow03_Inv(ConstFixedFunctionOpDataRcPtr & data,
float glowGain, float glowMid);
Renderer_ACES_Glow03_Inv(ConstFixedFunctionOpDataRcPtr & data, float glowGain, float glowMid);
void apply(const void * inImg, void * outImg, long numPixels) const override;
};
@@ -96,8 +88,6 @@ class Renderer_ACES_DarkToDim10_Fwd : public OpCPU
{
public:
Renderer_ACES_DarkToDim10_Fwd() = delete;
Renderer_ACES_DarkToDim10_Fwd(const Renderer_ACES_RedMod03_Fwd &) = delete;
Renderer_ACES_DarkToDim10_Fwd(ConstFixedFunctionOpDataRcPtr & data, float gamma);
void apply(const void * inImg, void * outImg, long numPixels) const override;
@@ -110,8 +100,6 @@ class Renderer_ACES_GamutComp13_Fwd : public OpCPU
{
public:
Renderer_ACES_GamutComp13_Fwd() = delete;
Renderer_ACES_GamutComp13_Fwd(const Renderer_ACES_GamutComp13_Fwd &) = delete;
explicit Renderer_ACES_GamutComp13_Fwd(ConstFixedFunctionOpDataRcPtr & data);
void apply(const void * inImg, void * outImg, long numPixels) const override;
@@ -142,8 +130,6 @@ class Renderer_REC2100_Surround : public OpCPU
{
public:
Renderer_REC2100_Surround() = delete;
Renderer_REC2100_Surround(const Renderer_ACES_RedMod03_Fwd &) = delete;
explicit Renderer_REC2100_Surround(ConstFixedFunctionOpDataRcPtr & data);
void apply(const void * inImg, void * outImg, long numPixels) const override;
@@ -156,8 +142,6 @@ class Renderer_RGB_TO_HSV : public OpCPU
{
public:
Renderer_RGB_TO_HSV() = delete;
Renderer_RGB_TO_HSV(const Renderer_ACES_RedMod03_Fwd &) = delete;
explicit Renderer_RGB_TO_HSV(ConstFixedFunctionOpDataRcPtr & data);
void apply(const void * inImg, void * outImg, long numPixels) const override;
@@ -167,8 +151,6 @@ class Renderer_HSV_TO_RGB : public OpCPU
{
public:
Renderer_HSV_TO_RGB() = delete;
Renderer_HSV_TO_RGB(const Renderer_ACES_RedMod03_Fwd &) = delete;
explicit Renderer_HSV_TO_RGB(ConstFixedFunctionOpDataRcPtr & data);
void apply(const void * inImg, void * outImg, long numPixels) const override;
@@ -178,8 +160,6 @@ class Renderer_XYZ_TO_xyY : public OpCPU
{
public:
Renderer_XYZ_TO_xyY() = delete;
Renderer_XYZ_TO_xyY(const Renderer_ACES_RedMod03_Fwd &) = delete;
explicit Renderer_XYZ_TO_xyY(ConstFixedFunctionOpDataRcPtr & data);
void apply(const void * inImg, void * outImg, long numPixels) const override;
@@ -189,8 +169,6 @@ class Renderer_xyY_TO_XYZ : public OpCPU
{
public:
Renderer_xyY_TO_XYZ() = delete;
Renderer_xyY_TO_XYZ(const Renderer_ACES_RedMod03_Fwd &) = delete;
explicit Renderer_xyY_TO_XYZ(ConstFixedFunctionOpDataRcPtr & data);
void apply(const void * inImg, void * outImg, long numPixels) const override;
@@ -200,8 +178,6 @@ class Renderer_XYZ_TO_uvY : public OpCPU
{
public:
Renderer_XYZ_TO_uvY() = delete;
Renderer_XYZ_TO_uvY(const Renderer_ACES_RedMod03_Fwd &) = delete;
explicit Renderer_XYZ_TO_uvY(ConstFixedFunctionOpDataRcPtr & data);
void apply(const void * inImg, void * outImg, long numPixels) const override;
@@ -211,8 +187,6 @@ class Renderer_uvY_TO_XYZ : public OpCPU
{
public:
Renderer_uvY_TO_XYZ() = delete;
Renderer_uvY_TO_XYZ(const Renderer_ACES_RedMod03_Fwd &) = delete;
explicit Renderer_uvY_TO_XYZ(ConstFixedFunctionOpDataRcPtr & data);
void apply(const void * inImg, void * outImg, long numPixels) const override;
@@ -222,8 +196,6 @@ class Renderer_XYZ_TO_LUV : public OpCPU
{
public:
Renderer_XYZ_TO_LUV() = delete;
Renderer_XYZ_TO_LUV(const Renderer_ACES_RedMod03_Fwd &) = delete;
explicit Renderer_XYZ_TO_LUV(ConstFixedFunctionOpDataRcPtr & data);
void apply(const void * inImg, void * outImg, long numPixels) const override;
@@ -233,8 +205,6 @@ class Renderer_LUV_TO_XYZ : public OpCPU
{
public:
Renderer_LUV_TO_XYZ() = delete;
Renderer_LUV_TO_XYZ(const Renderer_ACES_RedMod03_Fwd &) = delete;
explicit Renderer_LUV_TO_XYZ(ConstFixedFunctionOpDataRcPtr & data);
void apply(const void * inImg, void * outImg, long numPixels) const override;
@@ -279,10 +249,10 @@ __inline float CalcHueWeight(const float red, const float grn, const float blu,
{
// Convert RGB to Yab (luma/chroma).
const float a = 2.f * red - (grn + blu);
static const float sqrt3 = 1.7320508075688772f;
static constexpr float sqrt3 = 1.7320508075688772f;
const float b = sqrt3 * (grn - blu);
const float hue = atan2f(b, a);
const float hue = std::atan2(b, a);
// NB: The code in RedMod03 apply() assumes that in the range of the modification
// window that red will be the largest channel. The center and width must be
@@ -302,7 +272,7 @@ __inline float CalcHueWeight(const float red, const float grn, const float blu,
// These are the coefficients for a quadratic B-spline basis function.
// (All coefs taken from the ACES ctl code on github.)
static const float _M[4][4] = {
static constexpr float _M[4][4] = {
{ 0.25f, 0.00f, 0.00f, 0.00f},
{-0.75f, 0.75f, 0.75f, 0.25f},
{ 0.75f, -1.50f, 0.00f, 1.00f},
@@ -667,7 +637,7 @@ void Renderer_ACES_DarkToDim10_Fwd::apply(const void * inImg, void * outImg, lon
// With the modest 2% ACES surround, this minLum allows the min/max gain
// applied to dark colors to be about 0.6 to 1.6.
constexpr float minLum = 1e-10f;
static constexpr float minLum = 1e-10f;
// Calculate luminance assuming input is AP1 RGB.
const float Y = std::max( minLum, ( 0.27222871678091454f * red +
@@ -676,7 +646,7 @@ void Renderer_ACES_DarkToDim10_Fwd::apply(const void * inImg, void * outImg, lon
// TODO: Currently our fast approx. requires SSE registers.
// Either make this whole routine SSE or make fast scalar pow.
const float Ypow_over_Y = powf(Y, m_gamma);
const float Ypow_over_Y = std::pow(Y, m_gamma);
out[0] = red * Ypow_over_Y;
out[1] = grn * Ypow_over_Y;
+3 -3
View File
@@ -720,7 +720,7 @@ void GammaMoncurveMirrorOpCPUFwd::apply(const void * inImg, void * outImg, long
for (long idx = 0; idx<numPixels; ++idx)
{
const float sign[4] = { std::copysign(1.0f, in[0]), std::copysign(1.0f, in[1]),
std::copysign(1.0f, in[0]), std::copysign(1.0f, in[3]) };
std::copysign(1.0f, in[2]), std::copysign(1.0f, in[3]) };
const float pixel[4] = { std::fabs(in[0]), std::fabs(in[1]),
std::fabs(in[2]), std::fabs(in[3]) };
@@ -817,7 +817,7 @@ void GammaMoncurveMirrorOpCPURev::apply(const void * inImg, void * outImg, long
for (long idx = 0; idx<numPixels; ++idx)
{
const float sign[4] = { std::copysign(1.0f, in[0]), std::copysign(1.0f, in[1]),
std::copysign(1.0f, in[0]), std::copysign(1.0f, in[3]) };
std::copysign(1.0f, in[2]), std::copysign(1.0f, in[3]) };
const float pixel[4] = { std::fabs(in[0]), std::fabs(in[1]),
std::fabs(in[2]), std::fabs(in[3]) };
@@ -837,4 +837,4 @@ void GammaMoncurveMirrorOpCPURev::apply(const void * inImg, void * outImg, long
}
}
} // namespace OCIO_NAMESPACE
} // namespace OCIO_NAMESPACE
-4
View File
@@ -110,7 +110,6 @@ void AddBasicPassThruFwdShader(GpuShaderCreatorRcPtr & shaderCreator,
const double alphaGamma = gamma->getAlphaParams()[0];
const std::string pxl(shaderCreator->getPixelName());
const std::string pxlrgb(pxl + ".rgb");
ss.declareFloat4("gamma", redGamma, grnGamma, bluGamma, alphaGamma);
ss.declareFloat4("breakPnt", 0.f, 0.f, 0.f, 0.f);
@@ -139,7 +138,6 @@ void AddBasicPassThruRevShader(GpuShaderCreatorRcPtr & shaderCreator,
const double alphaGamma = 1. / gamma->getAlphaParams()[0];
const std::string pxl(shaderCreator->getPixelName());
const std::string pxlrgb(pxl + ".rgb");
ss.declareFloat4("gamma", redGamma, grnGamma, bluGamma, alphaGamma);
ss.declareFloat4("breakPnt", 0.f, 0.f, 0.f, 0.f);
@@ -171,7 +169,6 @@ void AddMoncurveFwdShader(GpuShaderCreatorRcPtr & shaderCreator,
ComputeParamsFwd(gamma->getAlphaParams(), alpha);
const std::string pxl(shaderCreator->getPixelName());
const std::string pxlrgb(pxl + ".rgb");
// Even if all components are the same, on OS X, a vec4 needs to be
// declared. This code will work in both cases.
@@ -210,7 +207,6 @@ void AddMoncurveRevShader(GpuShaderCreatorRcPtr & shaderCreator,
ComputeParamsRev(gamma->getAlphaParams(), alpha);
const std::string pxl(shaderCreator->getPixelName());
const std::string pxlrgb(pxl + ".rgb");
// Even if all components are the same, on OS X, a vec4 needs to be
// declared. This code will work in both cases.
@@ -76,12 +76,14 @@ void AddUniform(GpuShaderCreatorRcPtr & shaderCreator,
static constexpr char opPrefix[] = "grading_primary";
void AddGPLogProperties(GpuShaderCreatorRcPtr & shaderCreator, GpuShaderText & st,
void AddGPLogProperties(GpuShaderCreatorRcPtr & shaderCreator,
GpuShaderText & st,
ConstGradingPrimaryOpDataRcPtr & gpData,
GPProperties & propNames)
GPProperties & propNames,
bool dyn)
{
auto prop = gpData->getDynamicPropertyInternal();
if (gpData->isDynamic() && shaderCreator->getLanguage() != LANGUAGE_OSL_1)
if (dyn)
{
// Build names. No need to add an index to the name to avoid collisions as the dynamic
// properties are unique.
@@ -142,22 +144,12 @@ void AddGPLogProperties(GpuShaderCreatorRcPtr & shaderCreator, GpuShaderText & s
st.declareFloat3(propNames.contrast, comp.getContrast());
st.declareFloat3(propNames.gamma, comp.getGamma());
st.declareVar(propNames.pivot, static_cast<float>(comp.getPivot()));
st.declareVar(propNames.pivotBlack, static_cast<float>(value.m_pivotBlack));
st.declareVar(propNames.pivotWhite, static_cast<float>(value.m_pivotWhite));
st.declareVar(propNames.clampBlack, static_cast<float>(value.m_clampBlack));
st.declareVar(propNames.clampWhite, static_cast<float>(value.m_clampWhite));
st.declareVar(propNames.saturation, static_cast<float>(value.m_saturation));
if (shaderCreator->getLanguage() == LANGUAGE_OSL_1 && prop->isDynamic())
{
std::string msg("The dynamic properties are not yet supported by the 'Open Shading language"\
" (OSL)' translation: The '");
msg += opPrefix;
msg += "' dynamic property is replaced by a local variable.";
LogWarning(msg);
}
st.declareVarConst(propNames.pivot, static_cast<float>(comp.getPivot()));
st.declareVarConst(propNames.pivotBlack, static_cast<float>(value.m_pivotBlack));
st.declareVarConst(propNames.pivotWhite, static_cast<float>(value.m_pivotWhite));
st.declareVarConst(propNames.clampBlack, static_cast<float>(value.m_clampBlack));
st.declareVarConst(propNames.clampWhite, static_cast<float>(value.m_clampWhite));
st.declareVarConst(propNames.saturation, static_cast<float>(value.m_saturation));
}
}
@@ -173,7 +165,7 @@ void AddGPLogForwardShader(GpuShaderCreatorRcPtr & shaderCreator,
<< " + " << props.pivot << ";";
// Not sure if the if helps performance, but it does allow out == in at the default values.
st.newLine() << "if ( " << props.gamma << " != " << st.float3Const(1.f) << " )";
st.newLine() << "if ( " << st.vectorCompareExpression(props.gamma, "!=", st.float3Const(1.f)) << " )";
st.newLine() << "{";
st.indent();
st.newLine() << st.float3Decl("normalizedOut")
@@ -214,7 +206,7 @@ void AddGPLogInverseShader(GpuShaderCreatorRcPtr & shaderCreator,
st.newLine() << "}";
// Not sure if the if helps performance, but it does allow out == in at the default values.
st.newLine() << "if ( " << props.gamma << " != " << st.float3Const(1.f) << " )";
st.newLine() << "if ( " << st.vectorCompareExpression(props.gamma, "!=", st.float3Const(1.f)) << " )";
st.newLine() << "{";
st.indent();
st.newLine() << st.float3Decl("normalizedOut")
@@ -235,12 +227,14 @@ void AddGPLogInverseShader(GpuShaderCreatorRcPtr & shaderCreator,
st.newLine() << pxl << ".rgb += " << props.brightness << ";";
}
void AddGPLinProperties(GpuShaderCreatorRcPtr & shaderCreator, GpuShaderText & st,
void AddGPLinProperties(GpuShaderCreatorRcPtr & shaderCreator,
GpuShaderText & st,
ConstGradingPrimaryOpDataRcPtr & gpData,
GPProperties & propNames)
GPProperties & propNames,
bool dyn)
{
auto prop = gpData->getDynamicPropertyInternal();
if (gpData->isDynamic())
if (dyn)
{
// Build names. No need to add an index to the name to avoid collisions as the dynamic
// properties are unique.
@@ -294,10 +288,10 @@ void AddGPLinProperties(GpuShaderCreatorRcPtr & shaderCreator, GpuShaderText & s
st.declareFloat3(propNames.exposure, comp.getExposure());
st.declareFloat3(propNames.contrast, comp.getContrast());
st.declareVar(propNames.pivot, static_cast<float>(comp.getPivot()));
st.declareVar(propNames.clampBlack, static_cast<float>(value.m_clampBlack));
st.declareVar(propNames.clampWhite, static_cast<float>(value.m_clampWhite));
st.declareVar(propNames.saturation, static_cast<float>(value.m_saturation));
st.declareVarConst(propNames.pivot, static_cast<float>(comp.getPivot()));
st.declareVarConst(propNames.clampBlack, static_cast<float>(value.m_clampBlack));
st.declareVarConst(propNames.clampWhite, static_cast<float>(value.m_clampWhite));
st.declareVarConst(propNames.saturation, static_cast<float>(value.m_saturation));
}
}
@@ -313,7 +307,7 @@ void AddGPLinForwardShader(GpuShaderCreatorRcPtr & shaderCreator,
// Not sure if the if helps performance, but it does allow out == in at the default values.
// Although note that the log-to-lin in Tone Op also prevents out == in.
st.newLine() << "if ( " << props.contrast << " != " << st.float3Const(1.f) << " )";
st.newLine() << "if ( " << st.vectorCompareExpression(props.contrast, "!=", st.float3Const(1.f)) << " )";
st.newLine() << "{";
st.indent();
@@ -351,7 +345,7 @@ void AddGPLinInverseShader(GpuShaderCreatorRcPtr & shaderCreator,
// Not sure if the if helps performance, but it does allow out == in at the default values.
// Although note that the log-to-lin in Tone Op also prevents out == in.
st.newLine() << "if ( " << props.contrast << " != " << st.float3Const(1.f) << " )";
st.newLine() << "if ( " << st.vectorCompareExpression(props.contrast, "!=", st.float3Const(1.f)) << " )";
st.newLine() << "{";
st.indent();
// NB: The sign(outColor.rgb) is a vec3, preserving the sign of each channel.
@@ -366,12 +360,14 @@ void AddGPLinInverseShader(GpuShaderCreatorRcPtr & shaderCreator,
st.newLine() << pxl << ".rgb += " << props.offset << ";";
}
void AddGPVideoProperties(GpuShaderCreatorRcPtr & shaderCreator, GpuShaderText & st,
void AddGPVideoProperties(GpuShaderCreatorRcPtr & shaderCreator,
GpuShaderText & st,
ConstGradingPrimaryOpDataRcPtr & gpData,
GPProperties & propNames)
GPProperties & propNames,
bool dyn)
{
auto prop = gpData->getDynamicPropertyInternal();
if (gpData->isDynamic())
if (dyn)
{
// Build names. No need to add an index to the name to avoid collisions as the dynamic
// properties are unique.
@@ -431,11 +427,11 @@ void AddGPVideoProperties(GpuShaderCreatorRcPtr & shaderCreator, GpuShaderText &
st.declareFloat3(propNames.offset, comp.getOffset());
st.declareFloat3(propNames.slope, comp.getSlope());
st.declareVar(propNames.pivotBlack, static_cast<float>(value.m_pivotBlack));
st.declareVar(propNames.pivotWhite, static_cast<float>(value.m_pivotWhite));
st.declareVar(propNames.clampBlack, static_cast<float>(value.m_clampBlack));
st.declareVar(propNames.clampWhite, static_cast<float>(value.m_clampWhite));
st.declareVar(propNames.saturation, static_cast<float>(value.m_saturation));
st.declareVarConst(propNames.pivotBlack, static_cast<float>(value.m_pivotBlack));
st.declareVarConst(propNames.pivotWhite, static_cast<float>(value.m_pivotWhite));
st.declareVarConst(propNames.clampBlack, static_cast<float>(value.m_clampBlack));
st.declareVarConst(propNames.clampWhite, static_cast<float>(value.m_clampWhite));
st.declareVarConst(propNames.saturation, static_cast<float>(value.m_saturation));
}
}
@@ -450,7 +446,7 @@ void AddGPVideoForwardShader(GpuShaderCreatorRcPtr & shaderCreator,
<< " + " << props.pivotBlack << ";";
// Not sure if the if helps performance, but it does allow out == in at the default values.
st.newLine() << "if ( " << props.gamma << " != " << st.float3Const(1.f) << " )";
st.newLine() << "if ( " << st.vectorCompareExpression(props.gamma, "!=", st.float3Const(1.f)) << " )";
st.newLine() << "{";
st.indent();
st.newLine() << st.float3Decl("normalizedOut")
@@ -490,7 +486,7 @@ void AddGPVideoInverseShader(GpuShaderCreatorRcPtr & shaderCreator,
st.newLine() << "}";
// Not sure if the if helps performance, but it does allow out == in at the default values.
st.newLine() << "if ( " << props.gamma << " != " << st.float3Const(1.f) << " )";
st.newLine() << "if ( " << st.vectorCompareExpression(props.gamma, "!=", st.float3Const(1.f)) << " )";
st.newLine() << "{";
st.indent();
st.newLine() << st.float3Decl("normalizedOut")
@@ -512,7 +508,7 @@ void AddGPVideoInverseShader(GpuShaderCreatorRcPtr & shaderCreator,
void GetGradingPrimaryGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
ConstGradingPrimaryOpDataRcPtr & gpData)
{
const bool dyn = gpData->isDynamic();
const bool dyn = gpData->isDynamic() && shaderCreator->getLanguage() != LANGUAGE_OSL_1;
if (!dyn)
{
auto propGP = gpData->getDynamicPropertyInternal();
@@ -522,6 +518,16 @@ void GetGradingPrimaryGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
}
}
if (gpData->isDynamic() && shaderCreator->getLanguage() == LANGUAGE_OSL_1)
{
std::string msg("The dynamic properties are not yet supported by the 'Open Shading language"\
" (OSL)' translation: The '");
msg += opPrefix;
msg += "' dynamic property is replaced by a local variable.";
LogWarning(msg);
}
const GradingStyle style = gpData->getStyle();
const TransformDirection dir = gpData->getDirection();
@@ -543,7 +549,7 @@ void GetGradingPrimaryGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
{
case GRADING_LOG:
{
AddGPLogProperties(shaderCreator, st, gpData, properties);
AddGPLogProperties(shaderCreator, st, gpData, properties, dyn);
if (dyn)
{
st.newLine() << "if (!" << properties.localBypass << ")";
@@ -570,7 +576,7 @@ void GetGradingPrimaryGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
}
case GRADING_LIN:
{
AddGPLinProperties(shaderCreator, st, gpData, properties);
AddGPLinProperties(shaderCreator, st, gpData, properties, dyn);
if (dyn)
{
st.newLine() << "if (!" << properties.localBypass << ")";
@@ -597,7 +603,7 @@ void GetGradingPrimaryGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
}
case GRADING_VIDEO:
{
AddGPVideoProperties(shaderCreator, st, gpData, properties);
AddGPVideoProperties(shaderCreator, st, gpData, properties, dyn);
if (dyn)
{
st.newLine() << "if (!" << properties.localBypass << ")";
@@ -192,7 +192,7 @@ void EstimateSlopes(const std::vector<GradingControlPoint> & ctrlPnts, std::vect
{
size_t j = i;
float DL = secantLen[i];
while ((j < numCtrlPnts - 2) && (fabs(secantSlope[j + 1] - secantSlope[j]) < 1e-6f))
while ((j < numCtrlPnts - 2) && (std::fabs(secantSlope[j + 1] - secantSlope[j]) < 1e-6f))
{
DL += secantLen[j + 1];
j++;
@@ -255,7 +255,7 @@ void FitSpline(const std::vector<GradingControlPoint> & ctrlPnts,
}
else
{
if (fabs(aa) > fabs(bb))
if (std::fabs(aa) > std::fabs(bb))
{
ksi = xi_pl1 + aa * del_x / (slopes[i + 1] - slopes[i]);
}
@@ -473,7 +473,7 @@ void GradingBSplineCurveImpl::AddShaderEval(GpuShaderText & st,
st.newLine() << "{";
st.newLine() << " float B = " << coefs << "[coefsOffs + coefsSets];";
st.newLine() << " float C = " << coefs << "[coefsOffs + coefsSets * 2];";
st.newLine() << " return (x - C) / B + knStart;";
st.newLine() << " return abs(B) < 1e-5 ? knStart : (x - C) / B + knStart;";
st.newLine() << "}";
st.newLine() << "else if (x >= knEndY)";
@@ -485,7 +485,7 @@ void GradingBSplineCurveImpl::AddShaderEval(GpuShaderText & st,
st.newLine() << " float t = knEnd - kn;";
st.newLine() << " float slope = 2. * A * t + B;";
st.newLine() << " float offs = ( A * t + B ) * t + C;";
st.newLine() << " return (x - offs) / slope + knEnd;";
st.newLine() << " return abs(slope) < 1e-5 ? knEnd : (x - offs) / slope + knEnd;";
st.newLine() << "}";
// else
@@ -584,7 +584,7 @@ float GradingBSplineCurveImpl::KnotsCoefs::evalCurveRev(int c, float y) const
{
const float B = m_coefsArray[coefsOffs + coefsSets];
const float C = m_coefsArray[coefsOffs + coefsSets * 2];
return (y - C) / B + knStart;
return std::fabs(B) < 1e-5f ? knStart : (y - C) / B + knStart;
}
else if (y >= knEndY)
{
@@ -595,7 +595,7 @@ float GradingBSplineCurveImpl::KnotsCoefs::evalCurveRev(int c, float y) const
const float t = knEnd - kn;
const float slope = 2.f * A * t + B;
const float offs = (A * t + B) * t + C;
return (y - offs) / slope + knEnd;
return std::fabs(slope) < 1e-5f ? knEnd : (y - offs) / slope + knEnd;
}
else
{
@@ -136,11 +136,11 @@ std::string BuildResourceNameIndexed(GpuShaderCreatorRcPtr & shaderCreator, cons
return name;
}
static const std::string opPrefix{ "grading_rgbcurve" };
void SetGCProperties(GpuShaderCreatorRcPtr & shaderCreator, bool dynamic, GCProperties & propNames)
{
static const std::string opPrefix{ "grading_rgbcurve" };
if (dynamic && shaderCreator->getLanguage() != LANGUAGE_OSL_1)
if (dynamic)
{
// If there are several dynamic ops, they will use the same names for uniforms.
propNames.m_knotsOffsets = BuildResourceName(shaderCreator, opPrefix,
@@ -168,16 +168,6 @@ void SetGCProperties(GpuShaderCreatorRcPtr & shaderCreator, bool dynamic, GCProp
propNames.m_coefs, resIndex);
propNames.m_eval = BuildResourceNameIndexed(shaderCreator, opPrefix,
propNames.m_eval, resIndex);
if (shaderCreator->getLanguage() == LANGUAGE_OSL_1 && dynamic)
{
std::string msg("The dynamic properties are not yet supported by the 'Open Shading language"\
" (OSL)' translation: The '");
msg += opPrefix;
msg += "' dynamic property is replaced by a local variable.";
LogWarning(msg);
}
}
}
@@ -217,13 +207,14 @@ void AddGCPropertiesUniforms(GpuShaderCreatorRcPtr & shaderCreator,
void AddCurveEvalMethodTextToShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
ConstGradingRGBCurveOpDataRcPtr & gcData,
const GCProperties & props)
const GCProperties & props,
bool dyn)
{
GpuShaderText st(shaderCreator->getLanguage());
// Dynamic version uses uniforms declared globaly. Non-dynamic version declares local
// Dynamic version uses uniforms declared globally. Non-dynamic version declares local
// variables in the op specific helper function.
if (!gcData->isDynamic() || shaderCreator->getLanguage() == LANGUAGE_OSL_1)
if (!dyn)
{
auto propGC = gcData->getDynamicPropertyInternal();
@@ -236,7 +227,7 @@ void AddCurveEvalMethodTextToShaderProgram(GpuShaderCreatorRcPtr & shaderCreator
}
st.newLine() << "";
if (shaderCreator->getLanguage() == LANGUAGE_OSL_1)
if (shaderCreator->getLanguage() == LANGUAGE_OSL_1 || shaderCreator->getLanguage() == GPU_LANGUAGE_MSL_2_0)
{
st.newLine() << st.floatKeyword() << " " << props.m_eval << "(int curveIdx, float x)";
}
@@ -261,7 +252,8 @@ void AddCurveEvalMethodTextToShaderProgram(GpuShaderCreatorRcPtr & shaderCreator
void AddGCForwardShader(GpuShaderCreatorRcPtr & shaderCreator,
GpuShaderText & st,
const GCProperties & props,
bool dyn, bool doLinToLog)
bool dyn,
bool doLinToLog)
{
if (dyn)
{
@@ -308,7 +300,8 @@ void AddGCForwardShader(GpuShaderCreatorRcPtr & shaderCreator,
void AddGCInverseShader(GpuShaderCreatorRcPtr & shaderCreator,
GpuShaderText & st,
const GCProperties & props,
bool dyn, bool doLinToLog)
bool dyn,
bool doLinToLog)
{
if (dyn)
{
@@ -356,7 +349,7 @@ void AddGCInverseShader(GpuShaderCreatorRcPtr & shaderCreator,
void GetGradingRGBCurveGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
ConstGradingRGBCurveOpDataRcPtr & gcData)
{
const bool dyn = gcData->isDynamic();
const bool dyn = gcData->isDynamic() && shaderCreator->getLanguage() != LANGUAGE_OSL_1;
if (!dyn)
{
auto propGC = gcData->getDynamicPropertyInternal();
@@ -366,6 +359,16 @@ void GetGradingRGBCurveGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
}
}
if (gcData->isDynamic() && shaderCreator->getLanguage() == LANGUAGE_OSL_1)
{
std::string msg("The dynamic properties are not yet supported by the 'Open Shading language"\
" (OSL)' translation: The '");
msg += opPrefix;
msg += "' dynamic property is replaced by a local variable.";
LogWarning(msg);
}
const GradingStyle style = gcData->getStyle();
const TransformDirection dir = gcData->getDirection();
@@ -397,12 +400,12 @@ void GetGradingRGBCurveGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
AddGCPropertiesUniforms(shaderCreator, shaderProp, properties);
// Add helper function plus global variables if they are not dynamic.
AddCurveEvalMethodTextToShaderProgram(shaderCreator, gcData, properties);
AddCurveEvalMethodTextToShaderProgram(shaderCreator, gcData, properties, dyn);
}
else
{
// Declare the op specific helper function.
AddCurveEvalMethodTextToShaderProgram(shaderCreator, gcData, properties);
AddCurveEvalMethodTextToShaderProgram(shaderCreator, gcData, properties, dyn);
}
const bool doLinToLog = (style == GRADING_LIN) && !gcData->getBypassLinToLog();
@@ -84,14 +84,16 @@ void AddBoolUniform(GpuShaderCreatorRcPtr & shaderCreator,
}
}
void AddGTProperties(GpuShaderCreatorRcPtr & shaderCreator, GpuShaderText & st,
ConstGradingToneOpDataRcPtr & gtData,
GTProperties & propNames)
{
static const std::string opPrefix{ "grading_tone" };
static const std::string opPrefix{ "grading_tone" };
void AddGTProperties(GpuShaderCreatorRcPtr & shaderCreator,
GpuShaderText & st,
ConstGradingToneOpDataRcPtr & gtData,
GTProperties & propNames,
bool dyn)
{
auto prop = gtData->getDynamicPropertyInternal();
if (gtData->isDynamic() && shaderCreator->getLanguage() != LANGUAGE_OSL_1)
if (dyn)
{
// Build names. No need to add an index to the name to avoid collisions as the dynamic
// properties are unique.
@@ -222,52 +224,42 @@ void AddGTProperties(GpuShaderCreatorRcPtr & shaderCreator, GpuShaderText & st,
const auto & value = prop->getValue();
const auto & compVal = prop->getComputedValue();
st.declareVar(propNames.blacksR, static_cast<float>(value.m_blacks.m_red));
st.declareVar(propNames.blacksG, static_cast<float>(value.m_blacks.m_green));
st.declareVar(propNames.blacksB, static_cast<float>(value.m_blacks.m_blue));
st.declareVar(propNames.blacksM, static_cast<float>(value.m_blacks.m_master));
st.declareVar(propNames.blacksS, static_cast<float>(compVal.m_blacksStart));
st.declareVar(propNames.blacksW, static_cast<float>(compVal.m_blacksWidth));
st.declareVarConst(propNames.blacksR, static_cast<float>(value.m_blacks.m_red));
st.declareVarConst(propNames.blacksG, static_cast<float>(value.m_blacks.m_green));
st.declareVarConst(propNames.blacksB, static_cast<float>(value.m_blacks.m_blue));
st.declareVarConst(propNames.blacksM, static_cast<float>(value.m_blacks.m_master));
st.declareVarConst(propNames.blacksS, static_cast<float>(compVal.m_blacksStart));
st.declareVarConst(propNames.blacksW, static_cast<float>(compVal.m_blacksWidth));
st.declareVar(propNames.shadowsR, static_cast<float>(value.m_shadows.m_red));
st.declareVar(propNames.shadowsG, static_cast<float>(value.m_shadows.m_green));
st.declareVar(propNames.shadowsB, static_cast<float>(value.m_shadows.m_blue));
st.declareVar(propNames.shadowsM, static_cast<float>(value.m_shadows.m_master));
st.declareVar(propNames.shadowsS, static_cast<float>(compVal.m_shadowsStart));
st.declareVar(propNames.shadowsW, static_cast<float>(compVal.m_shadowsWidth));
st.declareVarConst(propNames.shadowsR, static_cast<float>(value.m_shadows.m_red));
st.declareVarConst(propNames.shadowsG, static_cast<float>(value.m_shadows.m_green));
st.declareVarConst(propNames.shadowsB, static_cast<float>(value.m_shadows.m_blue));
st.declareVarConst(propNames.shadowsM, static_cast<float>(value.m_shadows.m_master));
st.declareVarConst(propNames.shadowsS, static_cast<float>(compVal.m_shadowsStart));
st.declareVarConst(propNames.shadowsW, static_cast<float>(compVal.m_shadowsWidth));
st.declareVar(propNames.midtonesR, static_cast<float>(value.m_midtones.m_red));
st.declareVar(propNames.midtonesG, static_cast<float>(value.m_midtones.m_green));
st.declareVar(propNames.midtonesB, static_cast<float>(value.m_midtones.m_blue));
st.declareVar(propNames.midtonesM, static_cast<float>(value.m_midtones.m_master));
st.declareVar(propNames.midtonesS, static_cast<float>(value.m_midtones.m_start));
st.declareVar(propNames.midtonesW, static_cast<float>(value.m_midtones.m_width));
st.declareVarConst(propNames.midtonesR, static_cast<float>(value.m_midtones.m_red));
st.declareVarConst(propNames.midtonesG, static_cast<float>(value.m_midtones.m_green));
st.declareVarConst(propNames.midtonesB, static_cast<float>(value.m_midtones.m_blue));
st.declareVarConst(propNames.midtonesM, static_cast<float>(value.m_midtones.m_master));
st.declareVarConst(propNames.midtonesS, static_cast<float>(value.m_midtones.m_start));
st.declareVarConst(propNames.midtonesW, static_cast<float>(value.m_midtones.m_width));
st.declareVar(propNames.highlightsR, static_cast<float>(value.m_highlights.m_red));
st.declareVar(propNames.highlightsG, static_cast<float>(value.m_highlights.m_green));
st.declareVar(propNames.highlightsB, static_cast<float>(value.m_highlights.m_blue));
st.declareVar(propNames.highlightsM, static_cast<float>(value.m_highlights.m_master));
st.declareVar(propNames.highlightsS, static_cast<float>(compVal.m_highlightsStart));
st.declareVar(propNames.highlightsW, static_cast<float>(compVal.m_highlightsWidth));
st.declareVarConst(propNames.highlightsR, static_cast<float>(value.m_highlights.m_red));
st.declareVarConst(propNames.highlightsG, static_cast<float>(value.m_highlights.m_green));
st.declareVarConst(propNames.highlightsB, static_cast<float>(value.m_highlights.m_blue));
st.declareVarConst(propNames.highlightsM, static_cast<float>(value.m_highlights.m_master));
st.declareVarConst(propNames.highlightsS, static_cast<float>(compVal.m_highlightsStart));
st.declareVarConst(propNames.highlightsW, static_cast<float>(compVal.m_highlightsWidth));
st.declareVar(propNames.whitesR, static_cast<float>(value.m_whites.m_red));
st.declareVar(propNames.whitesG, static_cast<float>(value.m_whites.m_green));
st.declareVar(propNames.whitesB, static_cast<float>(value.m_whites.m_blue));
st.declareVar(propNames.whitesM, static_cast<float>(value.m_whites.m_master));
st.declareVar(propNames.whitesS, static_cast<float>(compVal.m_whitesStart));
st.declareVar(propNames.whitesW, static_cast<float>(compVal.m_whitesWidth));
st.declareVarConst(propNames.whitesR, static_cast<float>(value.m_whites.m_red));
st.declareVarConst(propNames.whitesG, static_cast<float>(value.m_whites.m_green));
st.declareVarConst(propNames.whitesB, static_cast<float>(value.m_whites.m_blue));
st.declareVarConst(propNames.whitesM, static_cast<float>(value.m_whites.m_master));
st.declareVarConst(propNames.whitesS, static_cast<float>(compVal.m_whitesStart));
st.declareVarConst(propNames.whitesW, static_cast<float>(compVal.m_whitesWidth));
st.declareVar(propNames.sContrast, static_cast<float>(value.m_scontrast));
if (shaderCreator->getLanguage() == LANGUAGE_OSL_1 && prop->isDynamic())
{
std::string msg("The dynamic properties are not yet supported by the 'Open Shading language"\
" (OSL)' translation: The '");
msg += opPrefix;
msg += "' dynamic property is replaced by a local variable.";
LogWarning(msg);
}
st.declareVarConst(propNames.sContrast, static_cast<float>(value.m_scontrast));
}
}
@@ -542,12 +534,12 @@ void Add_MidsRev_Shader(GpuShaderCreatorRcPtr & shaderCreator,
}
else
{
st.newLine() << st.float3Decl("t") << " = " << pix << ".rgb;";
st.newLine() << st.float3Decl("outL") << ";";
st.newLine() << st.float3Decl("outM") << ";";
st.newLine() << st.float3Decl("outR") << ";";
st.newLine() << st.float3Decl("outR2") << ";";
st.newLine() << st.float3Decl("outR3") << ";";
st.newLine() << st.colorDecl("t") << " = " << pix << ".rgb;";
st.newLine() << st.colorDecl("outL") << ";";
st.newLine() << st.colorDecl("outM") << ";";
st.newLine() << st.colorDecl("outR") << ";";
st.newLine() << st.colorDecl("outR2") << ";";
st.newLine() << st.colorDecl("outR3") << ";";
// TODO: Would probably be better to call the preceding if-block 3 times
// rather than trying to do a float3 computation here. Extra computation is
@@ -603,25 +595,25 @@ void Add_MidsRev_Shader(GpuShaderCreatorRcPtr & shaderCreator,
st.dedent();
st.newLine() << "}";
st.newLine() << st.float3Decl("res") << ";";
st.newLine() << "res.x = (t.x < y1) ? outL.x : outM.x;";
st.newLine() << "res.y = (t.y < y1) ? outL.y : outM.y;";
st.newLine() << "res.z = (t.z < y1) ? outL.z : outM.z;";
st.newLine() << "res.x = (t.x > y2) ? outR.x : res.x;";
st.newLine() << "res.y = (t.y > y2) ? outR.y : res.y;";
st.newLine() << "res.z = (t.z > y2) ? outR.z : res.z;";
st.newLine() << "res.x = (t.x > y3) ? outR2.x : res.x;";
st.newLine() << "res.y = (t.y > y3) ? outR2.y : res.y;";
st.newLine() << "res.z = (t.z > y3) ? outR2.z : res.z;";
st.newLine() << "res.x = (t.x > y4) ? outR3.x : res.x;";
st.newLine() << "res.y = (t.y > y4) ? outR3.y : res.y;";
st.newLine() << "res.z = (t.z > y4) ? outR3.z : res.z;";
st.newLine() << "res.x = (t.x < y0) ? x0 + (t.x - y0) * m0 : res.x;";
st.newLine() << "res.y = (t.y < y0) ? x0 + (t.y - y0) * m0 : res.y;";
st.newLine() << "res.z = (t.z < y0) ? x0 + (t.z - y0) * m0 : res.z;";
st.newLine() << "res.x = (t.x > y5) ? x5 + (t.x - y5) * m5 : res.x;";
st.newLine() << "res.y = (t.y > y5) ? x5 + (t.y - y5) * m5 : res.y;";
st.newLine() << "res.z = (t.z > y5) ? x5 + (t.z - y5) * m5 : res.z;";
st.newLine() << st.colorDecl("res") << ";";
st.newLine() << "res.r = (t.r < y1) ? outL.r : outM.r;";
st.newLine() << "res.g = (t.g < y1) ? outL.g : outM.g;";
st.newLine() << "res.b = (t.b < y1) ? outL.b : outM.b;";
st.newLine() << "res.r = (t.r > y2) ? outR.r : res.r;";
st.newLine() << "res.g = (t.g > y2) ? outR.g : res.g;";
st.newLine() << "res.b = (t.b > y2) ? outR.b : res.b;";
st.newLine() << "res.r = (t.r > y3) ? outR2.r : res.r;";
st.newLine() << "res.g = (t.g > y3) ? outR2.g : res.g;";
st.newLine() << "res.b = (t.b > y3) ? outR2.b : res.b;";
st.newLine() << "res.r = (t.r > y4) ? outR3.r : res.r;";
st.newLine() << "res.g = (t.g > y4) ? outR3.g : res.g;";
st.newLine() << "res.b = (t.b > y4) ? outR3.b : res.b;";
st.newLine() << "res.r = (t.r < y0) ? x0 + (t.r - y0) * m0 : res.r;";
st.newLine() << "res.g = (t.g < y0) ? x0 + (t.g - y0) * m0 : res.g;";
st.newLine() << "res.b = (t.b < y0) ? x0 + (t.b - y0) * m0 : res.b;";
st.newLine() << "res.r = (t.r > y5) ? x5 + (t.r - y5) * m5 : res.r;";
st.newLine() << "res.g = (t.g > y5) ? x5 + (t.g - y5) * m5 : res.g;";
st.newLine() << "res.b = (t.b > y5) ? x5 + (t.b - y5) * m5 : res.b;";
st.newLine() << pix << ".rgb = res;";
}
@@ -707,12 +699,12 @@ void Add_FauxCubicFwdEval_Shader(GpuShaderCreatorRcPtr & shaderCreator,
}
else
{
st.newLine() << st.float3Decl("t") << " = " << pix << "." << channelSuffix << ";";
st.newLine() << st.float3Decl("res") << ";";
st.newLine() << st.float3Decl("tL") << ";";
st.newLine() << st.float3Decl("tR") << ";";
st.newLine() << st.float3Decl("fL") << ";";
st.newLine() << st.float3Decl("fR") << ";";
st.newLine() << st.colorDecl("t") << " = " << pix << "." << channelSuffix << ";";
st.newLine() << st.colorDecl("res") << ";";
st.newLine() << st.colorDecl("tL") << ";";
st.newLine() << st.colorDecl("tR") << ";";
st.newLine() << st.colorDecl("fL") << ";";
st.newLine() << st.colorDecl("fR") << ";";
}
st.newLine() << "tL = (t - x0) / (x1 - x0);";
@@ -729,15 +721,15 @@ void Add_FauxCubicFwdEval_Shader(GpuShaderCreatorRcPtr & shaderCreator,
}
else
{
st.newLine() << "res.x = (t.x < x1) ? fL.x : fR.x;";
st.newLine() << "res.y = (t.y < x1) ? fL.y : fR.y;";
st.newLine() << "res.z = (t.z < x1) ? fL.z : fR.z;";
st.newLine() << "res.x = (t.x < x0) ? y0 + (t.x - x0) * m0 : res.x;";
st.newLine() << "res.y = (t.y < x0) ? y0 + (t.y - x0) * m0 : res.y;";
st.newLine() << "res.z = (t.z < x0) ? y0 + (t.z - x0) * m0 : res.z;";
st.newLine() << "res.x = (t.x > x2) ? y2 + (t.x - x2) * m2 : res.x;";
st.newLine() << "res.y = (t.y > x2) ? y2 + (t.y - x2) * m2 : res.y;";
st.newLine() << "res.z = (t.z > x2) ? y2 + (t.z - x2) * m2 : res.z;";
st.newLine() << "res.r = (t.r < x1) ? fL.r : fR.r;";
st.newLine() << "res.g = (t.g < x1) ? fL.g : fR.g;";
st.newLine() << "res.b = (t.b < x1) ? fL.b : fR.b;";
st.newLine() << "res.r = (t.r < x0) ? y0 + (t.r - x0) * m0 : res.r;";
st.newLine() << "res.g = (t.g < x0) ? y0 + (t.g - x0) * m0 : res.g;";
st.newLine() << "res.b = (t.b < x0) ? y0 + (t.b - x0) * m0 : res.b;";
st.newLine() << "res.r = (t.r > x2) ? y2 + (t.r - x2) * m2 : res.r;";
st.newLine() << "res.g = (t.g > x2) ? y2 + (t.g - x2) * m2 : res.g;";
st.newLine() << "res.b = (t.b > x2) ? y2 + (t.b - x2) * m2 : res.b;";
}
st.newLine() << pix << "." << channelSuffix << " = res;";
}
@@ -759,14 +751,14 @@ void Add_FauxCubicRevEval_Shader(GpuShaderCreatorRcPtr & shaderCreator,
}
else
{
st.newLine() << st.float3Decl("t") << " = " << pix << "." << channelSuffix << ";";
st.newLine() << st.float3Decl("res") << ";";
st.newLine() << st.float3Decl("cL") << ";";
st.newLine() << st.float3Decl("cR") << ";";
st.newLine() << st.float3Decl("discrimL") << ";";
st.newLine() << st.float3Decl("discrimR") << ";";
st.newLine() << st.float3Decl("outL") << ";";
st.newLine() << st.float3Decl("outR") << ";";
st.newLine() << st.colorDecl("t") << " = " << pix << "." << channelSuffix << ";";
st.newLine() << st.colorDecl("res") << ";";
st.newLine() << st.colorDecl("cL") << ";";
st.newLine() << st.colorDecl("cR") << ";";
st.newLine() << st.colorDecl("discrimL") << ";";
st.newLine() << st.colorDecl("discrimR") << ";";
st.newLine() << st.colorDecl("outL") << ";";
st.newLine() << st.colorDecl("outR") << ";";
}
st.newLine() << "cL = y0 - t;";
@@ -787,15 +779,15 @@ void Add_FauxCubicRevEval_Shader(GpuShaderCreatorRcPtr & shaderCreator,
}
else
{
st.newLine() << "res.x = (t.x < y1) ? outL.x : outR.x;";
st.newLine() << "res.y = (t.y < y1) ? outL.y : outR.y;";
st.newLine() << "res.z = (t.z < y1) ? outL.z : outR.z;";
st.newLine() << "res.x = (t.x < y0) ? x0 + (t.x - y0) / m0 : res.x;";
st.newLine() << "res.y = (t.y < y0) ? x0 + (t.y - y0) / m0 : res.y;";
st.newLine() << "res.z = (t.z < y0) ? x0 + (t.z - y0) / m0 : res.z;";
st.newLine() << "res.x = (t.x > y2) ? x2 + (t.x - y2) / m2 : res.x;";
st.newLine() << "res.y = (t.y > y2) ? x2 + (t.y - y2) / m2 : res.y;";
st.newLine() << "res.z = (t.z > y2) ? x2 + (t.z - y2) / m2 : res.z;";
st.newLine() << "res.r = (t.r < y1) ? outL.r : outR.r;";
st.newLine() << "res.g = (t.g < y1) ? outL.g : outR.g;";
st.newLine() << "res.b = (t.b < y1) ? outL.b : outR.b;";
st.newLine() << "res.r = (t.r < y0) ? x0 + (t.r - y0) / m0 : res.r;";
st.newLine() << "res.g = (t.g < y0) ? x0 + (t.g - y0) / m0 : res.g;";
st.newLine() << "res.b = (t.b < y0) ? x0 + (t.b - y0) / m0 : res.b;";
st.newLine() << "res.r = (t.r > y2) ? x2 + (t.r - y2) / m2 : res.r;";
st.newLine() << "res.g = (t.g > y2) ? x2 + (t.g - y2) / m2 : res.g;";
st.newLine() << "res.b = (t.b > y2) ? x2 + (t.b - y2) / m2 : res.b;";
}
st.newLine() << pix << "." << channelSuffix << " = res;";
}
@@ -954,7 +946,7 @@ void Add_WhiteBlackPre_Shader(GpuShaderCreatorRcPtr & shaderCreator,
}
else
{
st.newLine() << st.float3Decl("t") << " = " << pix << ".rgb;";
st.newLine() << st.colorDecl("t") << " = " << pix << ".rgb;";
}
}
@@ -962,83 +954,83 @@ void Add_WBFwd_Shader(unsigned channel, bool linearExtrap, GpuShaderText & st)
{
if (channel != M)
{
st.newLine() << " float tlocal = (t - x0) / (x1 - x0);";
st.newLine() << " float res = tlocal * (x1 - x0) * ( tlocal * 0.5 * (m1 - m0) + m0 ) + y0;";
st.newLine() << " res = (t < x0) ? y0 + (t - x0) * m0 : res;";
st.newLine() << st.floatKeyword() << " tlocal = (t - x0) / (x1 - x0);";
st.newLine() << st.floatKeyword() << " res = tlocal * (x1 - x0) * ( tlocal * 0.5 * (m1 - m0) + m0 ) + y0;";
st.newLine() << "res = (t < x0) ? y0 + (t - x0) * m0 : res;";
}
else
{
st.newLine() << " " << st.float3Decl("tlocal") << " = (t - x0) / (x1 - x0);";
st.newLine() << " " << st.float3Decl("res") << " = tlocal * (x1 - x0) * ( tlocal * 0.5 * (m1 - m0) + m0 ) + y0;";
st.newLine() << " res.x = (t.x < x0) ? y0 + (t.x - x0) * m0 : res.x;";
st.newLine() << " res.y = (t.y < x0) ? y0 + (t.y - x0) * m0 : res.y;";
st.newLine() << " res.z = (t.z < x0) ? y0 + (t.z - x0) * m0 : res.z;";
st.newLine() << st.float3Decl("tlocal") << " = (t - x0) / (x1 - x0);";
st.newLine() << st.colorDecl("res") << " = tlocal * (x1 - x0) * ( tlocal * 0.5 * (m1 - m0) + m0 ) + y0;";
st.newLine() << "res.r = (t.r < x0) ? y0 + (t.r - x0) * m0 : res.r;";
st.newLine() << "res.g = (t.g < x0) ? y0 + (t.g - x0) * m0 : res.g;";
st.newLine() << "res.b = (t.b < x0) ? y0 + (t.b - x0) * m0 : res.b;";
}
if ( linearExtrap )
{
if (channel != M)
{
st.newLine() << " res = (t > x1) ? y1 + (t - x1) * m1 : res;";
st.newLine() << "res = (t > x1) ? y1 + (t - x1) * m1 : res;";
}
else
{
st.newLine() << " res.x = (t.x > x1) ? y1 + (t.x - x1) * m1 : res.x;";
st.newLine() << " res.y = (t.y > x1) ? y1 + (t.y - x1) * m1 : res.y;";
st.newLine() << " res.z = (t.z > x1) ? y1 + (t.z - x1) * m1 : res.z;";
st.newLine() << "res.r = (t.r > x1) ? y1 + (t.r - x1) * m1 : res.r;";
st.newLine() << "res.g = (t.g > x1) ? y1 + (t.g - x1) * m1 : res.g;";
st.newLine() << "res.b = (t.b > x1) ? y1 + (t.b - x1) * m1 : res.b;";
}
}
}
void Add_WBRev_Shader(unsigned channel, bool linearExtrap, GpuShaderText & st)
{
st.newLine() << " float a = 0.5 * (m1 - m0) * (x1 - x0);";
st.newLine() << " float b = m0 * (x1 - x0);";
st.newLine() << st.floatKeyword() << " a = 0.5 * (m1 - m0) * (x1 - x0);";
st.newLine() << st.floatKeyword() << " b = m0 * (x1 - x0);";
if (channel != M)
{
st.newLine() << " float c = y0 - t;";
st.newLine() << " float discrim = sqrt( b * b - 4. * a * c );";
st.newLine() << " float tmp = ( -2. * c ) / ( discrim + b );";
st.newLine() << " float res = tmp * (x1 - x0) + x0;";
st.newLine() << " res = (t < y0) ? x0 + (t - y0) / m0 : res;";
st.newLine() << st.floatKeyword() << " c = y0 - t;";
st.newLine() << st.floatKeyword() << " discrim = sqrt( b * b - 4. * a * c );";
st.newLine() << st.floatKeyword() << " tmp = ( -2. * c ) / ( discrim + b );";
st.newLine() << st.floatKeyword() << " res = tmp * (x1 - x0) + x0;";
st.newLine() << "res = (t < y0) ? x0 + (t - y0) / m0 : res;";
}
else
{
st.newLine() << " " << st.float3Decl("c") << " = y0 - t;";
st.newLine() << " " << st.float3Decl("discrim") << " = sqrt( b * b - 4. * a * c );";
st.newLine() << " " << st.float3Decl("tmp") << " = ( -2. * c ) / ( discrim + b );";
st.newLine() << " " << st.float3Decl("res") << " = tmp * (x1 - x0) + x0;";
st.newLine() << " res.x = (t.x < y0) ? x0 + (t.x - y0) / m0 : res.x;";
st.newLine() << " res.y = (t.y < y0) ? x0 + (t.y - y0) / m0 : res.y;";
st.newLine() << " res.z = (t.z < y0) ? x0 + (t.z - y0) / m0 : res.z;";
st.newLine() << st.float3Decl("c") << " = y0 - t;";
st.newLine() << st.float3Decl("discrim") << " = sqrt( b * b - 4. * a * c );";
st.newLine() << st.float3Decl("tmp") << " = ( -2. * c ) / ( discrim + b );";
st.newLine() << st.colorDecl("res") << " = tmp * (x1 - x0) + x0;";
st.newLine() << "res.r = (t.r < y0) ? x0 + (t.r - y0) / m0 : res.r;";
st.newLine() << "res.g = (t.g < y0) ? x0 + (t.g - y0) / m0 : res.g;";
st.newLine() << "res.b = (t.b < y0) ? x0 + (t.b - y0) / m0 : res.b;";
}
if ( linearExtrap )
{
if (channel != M)
{
st.newLine() << " res = (t > y1) ? x1 + (t - y1) / m1 : res;";
st.newLine() << "res = (t > y1) ? x1 + (t - y1) / m1 : res;";
}
else
{
// TODO: When m1 = 1., y1=x1, this becomes t.
st.newLine() << " res.x = (t.x > y1) ? x1 + (t.x - y1) / m1 : res.x;";
st.newLine() << " res.y = (t.y > y1) ? x1 + (t.y - y1) / m1 : res.y;";
st.newLine() << " res.z = (t.z > y1) ? x1 + (t.z - y1) / m1 : res.z;";
st.newLine() << "res.r = (t.r > y1) ? x1 + (t.r - y1) / m1 : res.r;";
st.newLine() << "res.g = (t.g > y1) ? x1 + (t.g - y1) / m1 : res.g;";
st.newLine() << "res.b = (t.b > y1) ? x1 + (t.b - y1) / m1 : res.b;";
}
}
}
void Add_WBExtrapPre_Shader(GpuShaderText & st)
{
st.newLine() << " res = (res - x0) / gain + x0;";
st.newLine() << "res = (res - x0) / gain + x0;";
// Quadratic extrapolation for better HDR control.
st.newLine() << " float new_y1 = (x1 - x0) / gain + x0;";
st.newLine() << " float xd = x0 + (x1 - x0) * 0.99;";
st.newLine() << " float md = m0 + (xd - x0) * (m1 - m0) / (x1 - x0);";
st.newLine() << " md = 1. / md;";
st.newLine() << " float aa = 0.5 * (1. / m1 - md) / (x1 - xd);";
st.newLine() << " float bb = 1. / m1 - 2. * aa * x1;";
st.newLine() << " float cc = new_y1 - bb * x1 - aa * x1 * x1;";
st.newLine() << " t = (t - x0) / gain + x0;";
st.newLine() << st.floatKeyword() << " new_y1 = (x1 - x0) / gain + x0;";
st.newLine() << st.floatKeyword() << " xd = x0 + (x1 - x0) * 0.99;";
st.newLine() << st.floatKeyword() << " md = m0 + (xd - x0) * (m1 - m0) / (x1 - x0);";
st.newLine() << "md = 1. / md;";
st.newLine() << st.floatKeyword() << " aa = 0.5 * (1. / m1 - md) / (x1 - xd);";
st.newLine() << st.floatKeyword() << " bb = 1. / m1 - 2. * aa * x1;";
st.newLine() << st.floatKeyword() << " cc = new_y1 - bb * x1 - aa * x1 * x1;";
st.newLine() << "t = (t - x0) / gain + x0;";
}
void Add_WhiteBlackFwd_Shader(GpuShaderCreatorRcPtr & shaderCreator,
@@ -1056,47 +1048,50 @@ void Add_WhiteBlackFwd_Shader(GpuShaderCreatorRcPtr & shaderCreator,
st.newLine() << "if (mtest < 1.)";
st.newLine() << "{";
st.indent();
if (!isBlack)
{
st.newLine() << " m1 = max( 0.01, m1 );";
st.newLine() << " float y1 = y0 + (m0 + m1) * (x1 - x0) * 0.5;";
st.newLine() << "m1 = max( 0.01, m1 );";
st.newLine() << st.floatKeyword() << " y1 = y0 + (m0 + m1) * (x1 - x0) * 0.5;";
}
else
{
st.newLine() << " m0 = max( 0.01, m0 );";
st.newLine() << " float y0 = y1 - (m0 + m1) * (x1 - x0) * 0.5;";
st.newLine() << "m0 = max( 0.01, m0 );";
st.newLine() << st.floatKeyword() << " y0 = y1 - (m0 + m1) * (x1 - x0) * 0.5;";
}
Add_WBFwd_Shader(channel, true, st);
if (channel != M)
{
st.newLine() << " " << pix << "." << channelSuffix << " = res;";
st.newLine() << pix << "." << channelSuffix << " = res;";
}
else
{
st.newLine() << " " << pix << ".rgb = res;";
st.newLine() << pix << ".rgb = res;";
}
st.dedent();
st.newLine() << "}";
// Slope is increasing case.
st.newLine() << "else if (mtest > 1.)";
st.newLine() << "{";
st.indent();
if (!isBlack)
{
st.newLine() << " m1 = 2. - m1;";
st.newLine() << " m1 = max( 0.01, m1 );";
st.newLine() << " float gain = (m0 + m1) * 0.5;";
st.newLine() << " t = (t - x0) * gain + x0;";
st.newLine() << "m1 = 2. - m1;";
st.newLine() << "m1 = max( 0.01, m1 );";
st.newLine() << st.floatKeyword() << " gain = (m0 + m1) * 0.5;";
st.newLine() << "t = (t - x0) * gain + x0;";
}
else
{
st.newLine() << " m0 = 2. - m0;";
st.newLine() << " m0 = max( 0.01, m0 );";
st.newLine() << " float y0 = y1 - (m0 + m1) * (x1 - x0) * 0.5;";
st.newLine() << " float gain = (m0 + m1) * 0.5;";
st.newLine() << " t = (t - x1) * gain + x1;";
st.newLine() << "m0 = 2. - m0;";
st.newLine() << "m0 = max( 0.01, m0 );";
st.newLine() << st.floatKeyword() << " y0 = y1 - (m0 + m1) * (x1 - x0) * 0.5;";
st.newLine() << st.floatKeyword() << " gain = (m0 + m1) * 0.5;";
st.newLine() << "t = (t - x1) * gain + x1;";
}
Add_WBRev_Shader(channel, isBlack, st);
@@ -1107,28 +1102,29 @@ void Add_WhiteBlackFwd_Shader(GpuShaderCreatorRcPtr & shaderCreator,
if (channel != M)
{
st.newLine() << " if (t > x1) res = (aa * t + bb) * t + cc;";
st.newLine() << "if (t > x1) res = (aa * t + bb) * t + cc;";
}
else
{
st.newLine() << " if (t.x > x1) res.x = (aa * t.x + bb) * t.x + cc;";
st.newLine() << " if (t.y > x1) res.y = (aa * t.y + bb) * t.y + cc;";
st.newLine() << " if (t.z > x1) res.z = (aa * t.z + bb) * t.z + cc;";
st.newLine() << "if (t.r > x1) res.r = (aa * t.r + bb) * t.r + cc;";
st.newLine() << "if (t.g > x1) res.g = (aa * t.g + bb) * t.g + cc;";
st.newLine() << "if (t.b > x1) res.b = (aa * t.b + bb) * t.b + cc;";
}
}
else
{
st.newLine() << " res = (res - x1) / gain + x1;";
st.newLine() << "res = (res - x1) / gain + x1;";
}
if (channel != M)
{
st.newLine() << " " << pix << "." << channelSuffix << " = res;";
st.newLine() << pix << "." << channelSuffix << " = res;";
}
else
{
st.newLine() << " " << pix << ".rgb = res;";
st.newLine() << pix << ".rgb = res;";
}
st.dedent();
st.newLine() << "}"; // else if (mtest > 1.)
st.dedent();
@@ -1148,15 +1144,16 @@ void Add_WhiteBlackRev_Shader(GpuShaderCreatorRcPtr & shaderCreator,
st.newLine() << "if (mtest < 1.)";
st.newLine() << "{";
st.indent();
if (!isBlack)
{
st.newLine() << " m1 = max( 0.01, m1 );";
st.newLine() << " float y1 = y0 + (m0 + m1) * (x1 - x0) * 0.5;";
st.newLine() << "m1 = max( 0.01, m1 );";
st.newLine() << st.floatKeyword() << " y1 = y0 + (m0 + m1) * (x1 - x0) * 0.5;";
}
else
{
st.newLine() << " m0 = max( 0.01, m0 );";
st.newLine() << " float y0 = y1 - (m0 + m1) * (x1 - x0) * 0.5;";
st.newLine() << "m0 = max( 0.01, m0 );";
st.newLine() << st.floatKeyword() << " y0 = y1 - (m0 + m1) * (x1 - x0) * 0.5;";
}
Add_WBRev_Shader(channel, true, st);
@@ -1165,32 +1162,34 @@ void Add_WhiteBlackRev_Shader(GpuShaderCreatorRcPtr & shaderCreator,
if (channel != M)
{
st.newLine() << " " << pix << "." << channelSuffix << " = res;";
st.newLine() << pix << "." << channelSuffix << " = res;";
}
else
{
st.newLine() << " " << pix << ".rgb = res;";
st.newLine() << pix << ".rgb = res;";
}
st.dedent();
st.newLine() << "}";
// Slope is increasing case.
st.newLine() << "else if (mtest > 1.)";
st.newLine() << "{";
st.indent();
if (!isBlack)
{
st.newLine() << " m1 = 2. - m1;";
st.newLine() << " m1 = max( 0.01, m1 );";
st.newLine() << " float gain = (m0 + m1) * 0.5;";
st.newLine() << " t = (t - x0) * gain + x0;";
st.newLine() << "m1 = 2. - m1;";
st.newLine() << "m1 = max( 0.01, m1 );";
st.newLine() << st.floatKeyword() << " gain = (m0 + m1) * 0.5;";
st.newLine() << "t = (t - x0) * gain + x0;";
}
else
{
st.newLine() << " m0 = 2. - m0;";
st.newLine() << " m0 = max( 0.01, m0 );";
st.newLine() << " float y0 = y1 - (m0 + m1) * (x1 - x0) * 0.5;";
st.newLine() << " float gain = (m0 + m1) * 0.5;";
st.newLine() << " t = (t - x1) * gain + x1;";
st.newLine() << "m0 = 2. - m0;";
st.newLine() << "m0 = max( 0.01, m0 );";
st.newLine() << st.floatKeyword() << " y0 = y1 - (m0 + m1) * (x1 - x0) * 0.5;";
st.newLine() << st.floatKeyword() << " gain = (m0 + m1) * 0.5;";
st.newLine() << "t = (t - x1) * gain + x1;";
}
Add_WBFwd_Shader(channel, isBlack, st);
@@ -1201,36 +1200,37 @@ void Add_WhiteBlackRev_Shader(GpuShaderCreatorRcPtr & shaderCreator,
if (channel != M)
{
st.newLine() << " float c = cc - t;";
st.newLine() << " float discrim = sqrt( bb * bb - 4. * aa * c );";
st.newLine() << " float res1 = ( -2. * c ) / ( discrim + bb );";
st.newLine() << " float brk = (aa * x1 + bb) * x1 + cc;";
st.newLine() << " res = (t < brk) ? res : res1;";
st.newLine() << st.floatKeyword() << " c = cc - t;";
st.newLine() << st.floatKeyword() << " discrim = sqrt( bb * bb - 4. * aa * c );";
st.newLine() << st.floatKeyword() << " res1 = ( -2. * c ) / ( discrim + bb );";
st.newLine() << st.floatKeyword() << " brk = (aa * x1 + bb) * x1 + cc;";
st.newLine() << "res = (t < brk) ? res : res1;";
}
else
{
st.newLine() << " " << st.float3Decl("c") << " = cc - t;";
st.newLine() << " " << st.float3Decl("discrim") << " = sqrt( bb * bb - 4. * aa * c );";
st.newLine() << " " << st.float3Decl("res1") << " = ( -2. * c ) / ( discrim + bb );";
st.newLine() << " float brk = (aa * x1 + bb) * x1 + cc;";
st.newLine() << " res.x = (t.x < brk) ? res.x : res1.x;";
st.newLine() << " res.y = (t.y < brk) ? res.y : res1.y;";
st.newLine() << " res.z = (t.z < brk) ? res.z : res1.z;";
st.newLine() << st.float3Decl("c") << " = cc - t;";
st.newLine() << st.float3Decl("discrim") << " = sqrt( bb * bb - 4. * aa * c );";
st.newLine() << st.colorDecl("res1") << " = ( -2. * c ) / ( discrim + bb );";
st.newLine() << st.floatKeyword() << " brk = (aa * x1 + bb) * x1 + cc;";
st.newLine() << "res.r = (t.r < brk) ? res.r : res1.r;";
st.newLine() << "res.g = (t.g < brk) ? res.g : res1.g;";
st.newLine() << "res.b = (t.b < brk) ? res.b : res1.b;";
}
}
else
{
st.newLine() << " res = (res - x1) / gain + x1;";
st.newLine() << "res = (res - x1) / gain + x1;";
}
if (channel != M)
{
st.newLine() << " " << pix << "." << channelSuffix << " = res;";
st.newLine() << pix << "." << channelSuffix << " = res;";
}
else
{
st.newLine() << " " << pix << ".rgb = res;";
st.newLine() << pix << ".rgb = res;";
}
st.dedent();
st.newLine() << "}"; // else if (mtest > 1.)
st.dedent();
@@ -1260,7 +1260,7 @@ void Add_SContrastTopPre_Shader(GpuShaderCreatorRcPtr & shaderCreator,
st.newLine() << st.floatKeywordConst() << " pivot = " << std::to_string(pivot) << ";";
st.newLine() << st.float3Decl("t") << " = " << pix << ".rgb;";
st.newLine() << st.colorDecl("t") << " = " << pix << ".rgb;";
// Top end
st.newLine() << "{"; // establish scope so local variable names won't conflict
@@ -1341,28 +1341,28 @@ void Add_SContrastFwd_Shader(GpuShaderCreatorRcPtr & shaderCreator,
st.newLine() << pix << ".rgb = (t - pivot) * contrast + pivot;";
st.newLine() << st.float3Decl("tR") << " = (t - x1) / (x2 - x1);";
st.newLine() << st.float3Decl("res") << " = tR * (x2 - x1) * ( tR * 0.5 * (m3 - m0) + m0 ) + y1;";
st.newLine() << st.colorDecl("res") << " = tR * (x2 - x1) * ( tR * 0.5 * (m3 - m0) + m0 ) + y1;";
st.newLine() << pix << ".rgb.r = (t.x > x1) ? res.x : " << pix << ".rgb.r;";
st.newLine() << pix << ".rgb.g = (t.y > x1) ? res.y : " << pix << ".rgb.g;";
st.newLine() << pix << ".rgb.b = (t.z > x1) ? res.z : " << pix << ".rgb.b;";
st.newLine() << pix << ".rgb.r = (t.x > x2) ? y2 + (t.x - x2) * m3 : " << pix << ".rgb.r;";
st.newLine() << pix << ".rgb.g = (t.y > x2) ? y2 + (t.y - x2) * m3 : " << pix << ".rgb.g;";
st.newLine() << pix << ".rgb.b = (t.z > x2) ? y2 + (t.z - x2) * m3 : " << pix << ".rgb.b;";
st.newLine() << pix << ".rgb.r = (t.r > x1) ? res.r : " << pix << ".rgb.r;";
st.newLine() << pix << ".rgb.g = (t.g > x1) ? res.g : " << pix << ".rgb.g;";
st.newLine() << pix << ".rgb.b = (t.b > x1) ? res.b : " << pix << ".rgb.b;";
st.newLine() << pix << ".rgb.r = (t.r > x2) ? y2 + (t.r - x2) * m3 : " << pix << ".rgb.r;";
st.newLine() << pix << ".rgb.g = (t.g > x2) ? y2 + (t.g - x2) * m3 : " << pix << ".rgb.g;";
st.newLine() << pix << ".rgb.b = (t.b > x2) ? y2 + (t.b - x2) * m3 : " << pix << ".rgb.b;";
st.dedent();
st.newLine() << "}"; // end local scope
Add_SContrastBottomPre_Shader(st, style);
st.newLine() << st.float3Decl("tR") << " = (t - x1) / (x2 - x1);";
st.newLine() << st.float3Decl("res") << " = tR * (x2 - x1) * ( tR * 0.5 * (m3 - m0) + m0 ) + y1;";
st.newLine() << st.colorDecl("res") << " = tR * (x2 - x1) * ( tR * 0.5 * (m3 - m0) + m0 ) + y1;";
st.newLine() << pix << ".rgb.r = (t.x < x2) ? res.x : " << pix << ".rgb.r;";
st.newLine() << pix << ".rgb.g = (t.y < x2) ? res.y : " << pix << ".rgb.g;";
st.newLine() << pix << ".rgb.b = (t.z < x2) ? res.z : " << pix << ".rgb.b;";
st.newLine() << pix << ".rgb.r = (t.x < x1) ? y1 + (t.x - x1) * m0 : " << pix << ".rgb.r;";
st.newLine() << pix << ".rgb.g = (t.y < x1) ? y1 + (t.y - x1) * m0 : " << pix << ".rgb.g;";
st.newLine() << pix << ".rgb.b = (t.z < x1) ? y1 + (t.z - x1) * m0 : " << pix << ".rgb.b;";
st.newLine() << pix << ".rgb.r = (t.r < x2) ? res.r : " << pix << ".rgb.r;";
st.newLine() << pix << ".rgb.g = (t.g < x2) ? res.g : " << pix << ".rgb.g;";
st.newLine() << pix << ".rgb.b = (t.b < x2) ? res.b : " << pix << ".rgb.b;";
st.newLine() << pix << ".rgb.r = (t.r < x1) ? y1 + (t.r - x1) * m0 : " << pix << ".rgb.r;";
st.newLine() << pix << ".rgb.g = (t.g < x1) ? y1 + (t.g - x1) * m0 : " << pix << ".rgb.g;";
st.newLine() << pix << ".rgb.b = (t.b < x1) ? y1 + (t.b - x1) * m0 : " << pix << ".rgb.b;";
st.dedent();
st.newLine() << "}"; // end local scope
@@ -1385,14 +1385,14 @@ void Add_SContrastRev_Shader(GpuShaderCreatorRcPtr & shaderCreator,
st.newLine() << st.floatDecl("b") << " = m0 * (x2 - x1);";
st.newLine() << st.floatDecl("a") << " = (m3 - m0) * 0.5 * (x2 - x1);";
st.newLine() << st.float3Decl("discrim") << " = sqrt( b * b - 4. * a * c );";
st.newLine() << st.float3Decl("res") << " = (x2 - x1) * (-2. * c) / ( discrim + b ) + x1;";
st.newLine() << st.colorDecl("res") << " = (x2 - x1) * (-2. * c) / ( discrim + b ) + x1;";
st.newLine() << pix << ".rgb.r = (t.x > y1) ? res.x : " << pix << ".rgb.r;";
st.newLine() << pix << ".rgb.g = (t.y > y1) ? res.y : " << pix << ".rgb.g;";
st.newLine() << pix << ".rgb.b = (t.z > y1) ? res.z : " << pix << ".rgb.b;";
st.newLine() << pix << ".rgb.r = (t.x > y2) ? x2 + (t.x - y2) / m3 : " << pix << ".rgb.r;";
st.newLine() << pix << ".rgb.g = (t.y > y2) ? x2 + (t.y - y2) / m3 : " << pix << ".rgb.g;";
st.newLine() << pix << ".rgb.b = (t.z > y2) ? x2 + (t.z - y2) / m3 : " << pix << ".rgb.b;";
st.newLine() << pix << ".rgb.r = (t.r > y1) ? res.r : " << pix << ".rgb.r;";
st.newLine() << pix << ".rgb.g = (t.g > y1) ? res.g : " << pix << ".rgb.g;";
st.newLine() << pix << ".rgb.b = (t.b > y1) ? res.b : " << pix << ".rgb.b;";
st.newLine() << pix << ".rgb.r = (t.r > y2) ? x2 + (t.r - y2) / m3 : " << pix << ".rgb.r;";
st.newLine() << pix << ".rgb.g = (t.g > y2) ? x2 + (t.g - y2) / m3 : " << pix << ".rgb.g;";
st.newLine() << pix << ".rgb.b = (t.b > y2) ? x2 + (t.b - y2) / m3 : " << pix << ".rgb.b;";
st.dedent();
st.newLine() << "}"; // end local scope
@@ -1402,14 +1402,14 @@ void Add_SContrastRev_Shader(GpuShaderCreatorRcPtr & shaderCreator,
st.newLine() << st.floatDecl("b") << " = m0 * (x2 - x1);";
st.newLine() << st.floatDecl("a") << " = (m3 - m0) * 0.5 * (x2 - x1);";
st.newLine() << st.float3Decl("discrim") << " = sqrt( b * b - 4. * a * c );";
st.newLine() << st.float3Decl("res") << " = (x2 - x1) * (-2. * c) / ( discrim + b ) + x1;";
st.newLine() << st.colorDecl("res") << " = (x2 - x1) * (-2. * c) / ( discrim + b ) + x1;";
st.newLine() << pix << ".rgb.r = (t.x > y2) ? " << pix << ".rgb.r : res.x;";
st.newLine() << pix << ".rgb.g = (t.y > y2) ? " << pix << ".rgb.g : res.y;";
st.newLine() << pix << ".rgb.b = (t.z > y2) ? " << pix << ".rgb.b : res.z;";
st.newLine() << pix << ".rgb.r = (t.x > y1) ? " << pix << ".rgb.r : x1 + (t.x - y1) / m0;";
st.newLine() << pix << ".rgb.g = (t.y > y1) ? " << pix << ".rgb.g : x1 + (t.y - y1) / m0;";
st.newLine() << pix << ".rgb.b = (t.z > y1) ? " << pix << ".rgb.b : x1 + (t.z - y1) / m0;";
st.newLine() << pix << ".rgb.r = (t.r > y2) ? " << pix << ".rgb.r : res.r;";
st.newLine() << pix << ".rgb.g = (t.g > y2) ? " << pix << ".rgb.g : res.g;";
st.newLine() << pix << ".rgb.b = (t.b > y2) ? " << pix << ".rgb.b : res.b;";
st.newLine() << pix << ".rgb.r = (t.r > y1) ? " << pix << ".rgb.r : x1 + (t.r - y1) / m0;";
st.newLine() << pix << ".rgb.g = (t.g > y1) ? " << pix << ".rgb.g : x1 + (t.g - y1) / m0;";
st.newLine() << pix << ".rgb.b = (t.b > y1) ? " << pix << ".rgb.b : x1 + (t.b - y1) / m0;";
st.dedent();
st.newLine() << "}"; // end local scope
@@ -1528,7 +1528,7 @@ void AddGTInverseShader(GpuShaderCreatorRcPtr & shaderCreator,
void GetGradingToneGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
ConstGradingToneOpDataRcPtr & gtData)
{
const bool dyn = gtData->isDynamic();
const bool dyn = gtData->isDynamic() && shaderCreator->getLanguage() != LANGUAGE_OSL_1;
if (!dyn)
{
auto propGT = gtData->getDynamicPropertyInternal();
@@ -1538,6 +1538,16 @@ void GetGradingToneGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
}
}
if (gtData->isDynamic() && shaderCreator->getLanguage() == LANGUAGE_OSL_1)
{
std::string msg("The dynamic properties are not yet supported by the 'Open Shading language"\
" (OSL)' translation: The '");
msg += opPrefix;
msg += "' dynamic property is replaced by a local variable.";
LogWarning(msg);
}
const GradingStyle style = gtData->getStyle();
const TransformDirection dir = gtData->getDirection();
@@ -1555,7 +1565,7 @@ void GetGradingToneGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
// Properties holds shader variables names and is initialized with undecorated names suitable
// for local variables.
GTProperties properties;
AddGTProperties(shaderCreator, st, gtData, properties);
AddGTProperties(shaderCreator, st, gtData, properties, dyn);
if (dyn)
{
+3 -10
View File
@@ -107,16 +107,9 @@ private:
// special case 16f/64k 1D LUT.
struct IndexPair
{
unsigned short valA;
unsigned short valB;
float fraction;
IndexPair()
{
valA = 0;
valB = 0;
fraction = 0.0f;
}
unsigned short valA = 0;
unsigned short valB = 0;
float fraction = 0.0f;
static IndexPair GetEdgeFloatValues(float fIn);
};
+8 -3
View File
@@ -201,9 +201,12 @@ void GetLut1DGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
// Add the LUT code to the OCIO shader program.
if (height > 1 || lutData->isInputHalfDomain())
if (height > 1 || lutData->isInputHalfDomain()
|| shaderCreator->getLanguage() == GPU_LANGUAGE_GLSL_ES_1_0
|| shaderCreator->getLanguage() == GPU_LANGUAGE_GLSL_ES_3_0)
{
// In case the 1D LUT length exceeds the 1D texture maximum length
// In case the 1D LUT length exceeds the 1D texture maximum length,
// or the language doesn't support 1D textures,
// a 2D texture is used.
{
@@ -321,7 +324,9 @@ void GetLut1DGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator,
ss.newLine() << "";
}
if (height > 1 || lutData->isInputHalfDomain())
if (height > 1 || lutData->isInputHalfDomain()
|| shaderCreator->getLanguage() == GPU_LANGUAGE_GLSL_ES_1_0
|| shaderCreator->getLanguage() == GPU_LANGUAGE_GLSL_ES_3_0)
{
const std::string str = name + "_computePos(" + shaderCreator->getPixelName();
+11 -8
View File
@@ -38,23 +38,26 @@ void GetMatrixGPUShaderProgram(GpuShaderCreatorRcPtr & shaderCreator, ConstMatri
if (matrix->isDiagonal())
{
ss.newLine() << "res = "
<< ss.float4Const((float)values[0],
(float)values[5],
(float)values[10],
(float)values[15])
<< " * res;";
<< ss.float4Const((float)values[0],
(float)values[5],
(float)values[10],
(float)values[15])
<< " * res;";
}
else
{
ss.newLine() << "res = " << ss.mat4fMul(&values[0], "res") << ";";
// NOTE: The in-place matrix computation is not supported by OSL so,
// a temporary variable is needed.
ss.newLine() << ss.float4Decl("tmp") << " = res;";
ss.newLine() << "res = " << ss.mat4fMul(&values[0], "tmp") << ";";
}
}
if (matrix->hasOffsets())
{
ss.newLine() << "res = "
<< ss.float4Const((float)offs[0], (float)offs[1], (float)offs[2], (float)offs[3])
<< " + res;";
<< ss.float4Const((float)offs[0], (float)offs[1], (float)offs[2], (float)offs[3])
<< " + res;";
}
ss.newLine() << pxl << ".rgb = " << ss.float3Const("res.x", "res.y", "res.z") << ";";
+1 -1
View File
@@ -38,7 +38,7 @@ BEGIN
VALUE "LegalCopyright", ""
VALUE "LegalTrademarks1", ""
VALUE "LegalTrademarks2", ""
VALUE "OriginalFilename", "@PROJECT_NAME@@OCIO_LIBNAME_SUFFIX@@LIBNAME_SUFFIX@.dll"
VALUE "OriginalFilename", "@PROJECT_NAME@@OCIO_LIBNAME_SUFFIX@_@OpenColorIO_VERSION_MAJOR@_@OpenColorIO_VERSION_MINOR@@LIBNAME_SUFFIX@.dll"
VALUE "ProductName", "@PROJECT_NAME@"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
+4 -2
View File
@@ -546,7 +546,8 @@ void LoadFileUncached(FileFormat * & returnFormat,
try
{
// Open the filePath
filestream.open(
Platform::OpenInputFileStream(
filestream,
filepath.c_str(),
tryFormat->isBinary()
? std::ios_base::binary : std::ios_base::in);
@@ -618,7 +619,8 @@ void LoadFileUncached(FileFormat * & returnFormat,
std::ifstream filestream;
try
{
filestream.open(filepath.c_str(), altFormat->isBinary()
Platform::OpenInputFileStream(
filestream, filepath.c_str(), altFormat->isBinary()
? std::ios_base::binary : std::ios_base::in);
if (!filestream.good())
{
+1 -1
View File
@@ -8,7 +8,7 @@ if(OCIO_BUILD_APPS)
add_subdirectory(ociomakeclf)
add_subdirectory(ociowrite)
if(TARGET OpenImageIO::OpenImageIO)
if(OpenImageIO_FOUND AND TARGET OpenImageIO::OpenImageIO)
add_subdirectory(ociolutimage)
add_subdirectory(ocioconvert)
add_subdirectory(ociodisplay)
+1 -1
View File
@@ -40,5 +40,5 @@ target_link_libraries(ociobakelut
)
install(TARGETS ociobakelut
RUNTIME DESTINATION bin
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
+1 -1
View File
@@ -28,5 +28,5 @@ target_link_libraries(ociocheck
)
install(TARGETS ociocheck
RUNTIME DESTINATION bin
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
+1 -1
View File
@@ -36,5 +36,5 @@ target_link_libraries(ociochecklut
)
install(TARGETS ociochecklut
RUNTIME DESTINATION bin
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
+1 -2
View File
@@ -27,7 +27,6 @@ set_target_properties(ocioconvert PROPERTIES
target_link_libraries(ocioconvert
PRIVATE
apputils
${OCIO_HALF_LIB}
${OCIO_GL_LIB}
oiiohelpers
OpenColorIO
@@ -35,5 +34,5 @@ target_link_libraries(ocioconvert
)
install(TARGETS ocioconvert
RUNTIME DESTINATION bin
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
+21 -1
View File
@@ -13,6 +13,16 @@ namespace OCIO = OCIO_NAMESPACE;
#include <OpenImageIO/imageio.h>
#include <OpenImageIO/typedesc.h>
// Take the half.h the same way OpenImageIO takes it i.e. do not use the Imath/OpenEXR one from
// OpenColorIO to avoid version clashes between OpenColorIO & OpenImageIO libraries. For example,
// OpenColorIO uses Imath 3.1.x but OpenImageIO (from the system) is using Imath 3.0.x which
// breaks the OpenColorIO compilation.
#if (OIIO_VERSION >= 20200)
# include <OpenImageIO/Imath.h>
#else
# include <OpenEXR/half.h>
#endif
#if (OIIO_VERSION < 10100)
namespace OIIO = OIIO_NAMESPACE;
#endif
@@ -24,7 +34,6 @@ namespace OIIO = OIIO_NAMESPACE;
#endif // OCIO_GPU_ENABLED
#include "oiiohelpers.h"
#include "utils/Half.h"
// Array of non OpenColorIO arguments.
@@ -616,6 +625,17 @@ int main(int argc, const char **argv)
exit(1);
}
if (useDisplayView)
{
OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
outputcolorspace = config->getDisplayViewColorSpaceName(display, view);
}
if (outputcolorspace)
{
spec.attribute("oiio:ColorSpace", outputcolorspace);
}
f->open(outputimage, spec);
if(!f->write_image(spec.format, img.getBuffer()))
+1 -1
View File
@@ -45,5 +45,5 @@ target_link_libraries(ociodisplay
OpenImageIO::OpenImageIO
)
install(TARGETS ociodisplay
RUNTIME DESTINATION bin
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
+31 -3
View File
@@ -31,13 +31,18 @@ namespace OCIO = OCIO_NAMESPACE;
#include <GL/gl.h>
#include <GL/glut.h>
#endif
#if __APPLE__
#include "metalapp.h"
#endif
#include "glsl.h"
#include "oglapp.h"
bool g_verbose = false;
bool g_gpulegacy = false;
bool g_gpuinfo = false;
#if __APPLE__
bool g_useMetal = false;
#endif
std::string g_filename;
@@ -414,7 +419,12 @@ void UpdateOCIOGLState()
// Set the shader context.
OCIO::GpuShaderDescRcPtr shaderDesc = OCIO::GpuShaderDesc::CreateShaderDesc();
shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_2);
shaderDesc->setLanguage(
#if __APPLE__
g_useMetal ?
OCIO::GPU_LANGUAGE_MSL_2_0 :
#endif
OCIO::GPU_LANGUAGE_GLSL_1_2);
shaderDesc->setFunctionName("OCIODisplay");
shaderDesc->setResourcePrefix("ocio_");
@@ -613,6 +623,12 @@ void parseArguments(int argc, char **argv)
{
g_gpuinfo = true;
}
#if __APPLE__
else if(0==strcmp(argv[i], "-metal"))
{
g_useMetal = true;
}
#endif
else if(0==strcmp(argv[i], "-h"))
{
std::cout << std::endl;
@@ -624,6 +640,9 @@ void parseArguments(int argc, char **argv)
std::cout << " -v : displays the color space information" << std::endl;
std::cout << " -gpulegacy : use the legacy (i.e. baked) GPU color processing" << std::endl;
std::cout << " -gpuinfo : output the OCIO shader program" << std::endl;
#if __APPLE__
std::cout << " -metal : use metal OCIO shader backend " << std::endl;
#endif
std::cout << std::endl;
exit(0);
}
@@ -640,7 +659,16 @@ int main(int argc, char **argv)
try
{
g_oglApp = std::make_shared<OCIO::ScreenApp>("ociodisplay", 512, 512);
#if __APPLE__
if(g_useMetal)
{
g_oglApp = std::make_shared<OCIO::MetalApp>("ociodisplay", 512, 512);
}
else
#endif
{
g_oglApp = std::make_shared<OCIO::ScreenApp>("ociodisplay", 512, 512);
}
}
catch (const OCIO::Exception & e)
{
+1 -1
View File
@@ -26,5 +26,5 @@ target_link_libraries(ociolutimage
)
install(TARGETS ociolutimage
RUNTIME DESTINATION bin
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
+1 -1
View File
@@ -29,5 +29,5 @@ target_link_libraries(ociomakeclf
)
install(TARGETS ociomakeclf
RUNTIME DESTINATION bin
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
+1 -3
View File
@@ -20,7 +20,6 @@ set_target_properties(ocioperf PROPERTIES
target_link_libraries(ocioperf
PRIVATE
apputils
${OCIO_HALF_LIB}
oiiohelpers
OpenColorIO
OpenImageIO::OpenImageIO
@@ -28,6 +27,5 @@ target_link_libraries(ocioperf
)
install(TARGETS ocioperf
RUNTIME DESTINATION bin
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
-1
View File
@@ -12,7 +12,6 @@ namespace OIIO = OIIO_NAMESPACE;
#include "apputils/argparse.h"
#include "oiiohelpers.h"
#include "utils/Half.h"
#include "utils/StringUtils.h"
+1 -2
View File
@@ -24,6 +24,5 @@ target_link_libraries(ociowrite
)
install(TARGETS ociowrite
RUNTIME DESTINATION bin
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
+38
View File
@@ -0,0 +1,38 @@
<!-- SPDX-License-Identifier: CC-BY-4.0 -->
<!-- Copyright Contributors to the OpenColorIO Project. -->
pyociodisplay
=============
**Work in progress**. Minimal image viewer implementation demonstrating use of
the OCIO GPU renderer in a Python application.
Usage
-----
1. Install dependencies on ``PYTHONPATH``
2. Run ``python pyociodisplay.py``
3. Load image with ``File/Load image...`` menu item
Dependencies
------------
* PyOpenColorIO
* [OpenImageIO (Python bindings)](https://github.com/OpenImageIO/oiio)
* [Imath (Python bindings)](https://github.com/AcademySoftwareFoundation/Imath)
* ``pip install requirements.txt``
* [numpy](https://pypi.org/project/numpy/)
* [PyOpenGL](https://pypi.org/project/PyOpenGL/)
* [PySide2](https://pypi.org/project/PySide2/)
Implementation notes
--------------------
* Assumes the ``OCIO`` environment variable is defined and pointing to a
compatible OCIO config file.
* Takes into account file and viewing rules, and may change the input color
space and/or view automatically when a new image is loaded.
* Exposure and gamma controls are dynamic parameters, driving uniforms in the
generated shader program.
* Specific channel views can be toggled with R, G, B, A keys, and the RGBA view
restored with C.
File diff suppressed because it is too large Load Diff
+3
View File
@@ -0,0 +1,3 @@
numpy
PyOpenGL
PySide2
+1 -1
View File
@@ -155,7 +155,7 @@ set_target_properties(OpenColorIO-JNI
# Installation
install(TARGETS OpenColorIO-JNI
DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/lib${LIB_SUFFIX}
DESTINATION ${CMAKE_INSTALL_EXEC_PREFIX}/${CMAKE_INSTALL_LIBDIR}
)
install(FILES ${JNIOCIO_JAR}
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/ocio/
+6 -6
View File
@@ -203,14 +203,14 @@ target_include_directories(PyOpenColorIO
# macOS, to prevent segfaults when potentially working with multiple Python
# installations. See note in:
# https://pybind11.readthedocs.io/en/stable/compiling.html#building-manually
set(PYOCIO_LINK_PUBLIC OpenColorIOHeaders)
if(WIN32)
list(INSERT PYOCIO_LINK_PUBLIC 0 ${Python_LIBRARIES})
if (WIN32)
set(_PublicLibs ${Python_LIBRARIES})
endif()
target_link_libraries(PyOpenColorIO
PUBLIC
${PYOCIO_LINK_PUBLIC}
${_PublicLibs}
PRIVATE
OpenColorIO
utils::strings
@@ -226,9 +226,9 @@ target_compile_definitions(PyOpenColorIO
)
if(WIN32)
set(_Python_VARIANT_PATH "lib${LIB_SUFFIX}/site-packages")
set(_Python_VARIANT_PATH "${CMAKE_INSTALL_LIBDIR}/site-packages")
else()
set(_Python_VARIANT_PATH "lib${LIB_SUFFIX}/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}/site-packages")
set(_Python_VARIANT_PATH "${CMAKE_INSTALL_LIBDIR}/python${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}/site-packages")
endif()
# Create an internal global variable to access it in another scope but not publicly visible
+2 -2
View File
@@ -117,7 +117,7 @@ void bindPyGpuShaderDesc(py::module & m)
const py::buffer & values)
{
py::buffer_info info = values.request();
ssize_t numChannels;
py::ssize_t numChannels;
switch (channel)
{
@@ -252,7 +252,7 @@ void bindPyGpuShaderDesc(py::module & m)
const float * values;
self.m_shaderDesc->getTextureValues(self.m_index, values);
ssize_t numChannels;
py::ssize_t numChannels;
switch (self.m_channel)
{
case GpuShaderDesc::TEXTURE_RED_CHANNEL:
+6
View File
@@ -514,8 +514,14 @@ void bindPyTypes(py::module & m)
DOC(PyOpenColorIO, GpuLanguage, GPU_LANGUAGE_GLSL_1_3))
.value("GPU_LANGUAGE_GLSL_4_0", GPU_LANGUAGE_GLSL_4_0,
DOC(PyOpenColorIO, GpuLanguage, GPU_LANGUAGE_GLSL_4_0))
.value("GPU_LANGUAGE_GLSL_ES_1_0", GPU_LANGUAGE_GLSL_ES_1_0,
DOC(PyOpenColorIO, GpuLanguage, GPU_LANGUAGE_GLSL_ES_1_0))
.value("GPU_LANGUAGE_GLSL_ES_3_0", GPU_LANGUAGE_GLSL_ES_3_0,
DOC(PyOpenColorIO, GpuLanguage, GPU_LANGUAGE_GLSL_ES_3_0))
.value("GPU_LANGUAGE_HLSL_DX11", GPU_LANGUAGE_HLSL_DX11,
DOC(PyOpenColorIO, GpuLanguage, GPU_LANGUAGE_HLSL_DX11))
.value("GPU_LANGUAGE_MSL_2_0", GPU_LANGUAGE_MSL_2_0,
DOC(PyOpenColorIO, GpuLanguage, GPU_LANGUAGE_MSL_2_0))
.export_values();
py::enum_<EnvironmentMode>(
+4 -4
View File
@@ -23,7 +23,7 @@ const std::vector<std::string> FLOAT_FORMATS = { "e", "f", "d", "g", "Ze", "Zf",
} // namespace
std::string formatCodeToDtypeName(const std::string & format, ssize_t numBits)
std::string formatCodeToDtypeName(const std::string & format, py::ssize_t numBits)
{
std::ostringstream os;
@@ -85,7 +85,7 @@ py::dtype bitDepthToDtype(BitDepth bitDepth)
return py::dtype(name);
}
ssize_t bitDepthToBytes(BitDepth bitDepth)
py::ssize_t bitDepthToBytes(BitDepth bitDepth)
{
std::string name, err;
@@ -179,7 +179,7 @@ void checkBufferType(const py::buffer_info & info, BitDepth bitDepth)
checkBufferType(info, bitDepthToDtype(bitDepth));
}
void checkBufferDivisible(const py::buffer_info & info, ssize_t numChannels)
void checkBufferDivisible(const py::buffer_info & info, py::ssize_t numChannels)
{
if (info.size % numChannels != 0)
{
@@ -190,7 +190,7 @@ void checkBufferDivisible(const py::buffer_info & info, ssize_t numChannels)
}
}
void checkBufferSize(const py::buffer_info & info, ssize_t numEntries)
void checkBufferSize(const py::buffer_info & info, py::ssize_t numEntries)
{
if (info.size != numEntries)
{
+4 -4
View File
@@ -61,11 +61,11 @@ private:
};
// Convert Python buffer protocol format code to NumPy dtype name
std::string formatCodeToDtypeName(const std::string & format, ssize_t numBits);
std::string formatCodeToDtypeName(const std::string & format, py::ssize_t numBits);
// Convert OCIO BitDepth to NumPy dtype
py::dtype bitDepthToDtype(BitDepth bitDepth);
// Convert OCIO BitDepth to data type byte count
ssize_t bitDepthToBytes(BitDepth bitDepth);
py::ssize_t bitDepthToBytes(BitDepth bitDepth);
// Convert OCIO ChannelOrdering to channel count
long chanOrderToNumChannels(ChannelOrdering chanOrder);
@@ -79,9 +79,9 @@ void checkBufferType(const py::buffer_info & info, const py::dtype & dt);
// Throw if Python buffer format is incompatible with an OCIO BitDepth
void checkBufferType(const py::buffer_info & info, BitDepth bitDepth);
// Throw if Python buffer size is not divisible by channel count
void checkBufferDivisible(const py::buffer_info & info, ssize_t numChannels);
void checkBufferDivisible(const py::buffer_info & info, py::ssize_t numChannels);
// Throw if Python buffer does not have an exact count of entries
void checkBufferSize(const py::buffer_info & info, ssize_t numEntries);
void checkBufferSize(const py::buffer_info & info, py::ssize_t numEntries);
// Calculate 3D grid size from a packed 3D LUT buffer
unsigned long getBufferLut3DGridSize(const py::buffer_info & info);
@@ -113,7 +113,7 @@ void bindPyLut1DTransform(py::module & m)
py::gil_scoped_acquire acquire;
return py::array(py::dtype("float32"),
{ static_cast<ssize_t>(values.size()) },
{ static_cast<py::ssize_t>(values.size()) },
{ sizeof(float) },
values.data());
})
@@ -128,7 +128,7 @@ void bindPyLut3DTransform(py::module & m)
py::gil_scoped_acquire acquire;
return py::array(py::dtype("float32"),
{ static_cast<ssize_t>(values.size()) },
{ static_cast<py::ssize_t>(values.size()) },
{ sizeof(float) },
values.data());
})
+29 -3
View File
@@ -15,6 +15,22 @@ set(INCLUDES
oglapp.h
)
if(APPLE)
list(APPEND SOURCES
msl.mm
mtltexture.mm
metalapp.mm
)
list(APPEND INCLUDES
msl.h
mtltexture.h
metalapp.h
)
endif()
add_library(oglapphelpers STATIC ${SOURCES})
set_target_properties(oglapphelpers PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(oglapphelpers PROPERTIES OUTPUT_NAME OpenColorIOoglapphelpers)
@@ -82,6 +98,16 @@ else()
)
endif()
if(APPLE)
target_link_libraries(oglapphelpers
PRIVATE
"-framework Carbon"
"-framework IOKit"
"-framework Metal"
"-framework CoreVideo"
)
endif()
if(${OCIO_EGL_HEADLESS})
target_include_directories(oglapphelpers
PRIVATE
@@ -90,10 +116,10 @@ if(${OCIO_EGL_HEADLESS})
endif()
install(TARGETS oglapphelpers
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(FILES ${INCLUDES}
DESTINATION include/OpenColorIO/oglapphelpers
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/OpenColorIO/oglapphelpers
)
+20 -9
View File
@@ -444,20 +444,31 @@ void OpenGLBuilder::useAllUniforms()
std::string OpenGLBuilder::getGLSLVersionString()
{
if (m_shaderDesc->getLanguage() == GPU_LANGUAGE_GLSL_1_3)
switch (m_shaderDesc->getLanguage())
{
case GPU_LANGUAGE_GLSL_1_2:
case GPU_LANGUAGE_MSL_2_0:
// That's the minimal version supported.
return "#version 120";
case GPU_LANGUAGE_GLSL_1_3:
return "#version 130";
}
else if (m_shaderDesc->getLanguage() == GPU_LANGUAGE_GLSL_4_0)
{
case GPU_LANGUAGE_GLSL_4_0:
return "#version 400 core";
case GPU_LANGUAGE_GLSL_ES_1_0:
return "#version 100";
case GPU_LANGUAGE_GLSL_ES_3_0:
return "#version 300 es";
case GPU_LANGUAGE_CG:
case GPU_LANGUAGE_HLSL_DX11:
case LANGUAGE_OSL_1:
default:
// These are all impossible in OpenGL contexts.
// The shader will be unusable, so let's throw
throw Exception("Invalid shader language for OpenGLBuilder");
}
// That's the minimal version supported.
return "#version 120";
}
unsigned OpenGLBuilder::buildProgram(const std::string & clientShaderProgram)
unsigned OpenGLBuilder::buildProgram(const std::string & clientShaderProgram, bool standaloneShader)
{
const std::string shaderCacheID = m_shaderDesc->getCacheID();
if(shaderCacheID!=m_shaderCacheID)
@@ -470,7 +481,7 @@ unsigned OpenGLBuilder::buildProgram(const std::string & clientShaderProgram)
std::ostringstream os;
os << getGLSLVersionString() << std::endl
<< m_shaderDesc->getShaderText() << std::endl
<< (!standaloneShader ? m_shaderDesc->getShaderText() : "") << std::endl
<< clientShaderProgram << std::endl;
if(m_verbose)
+1 -1
View File
@@ -79,7 +79,7 @@ public:
// Build the complete shader program which includes the OCIO shader program
// and the client shader program.
unsigned buildProgram(const std::string & clientShaderProgram);
unsigned buildProgram(const std::string & clientShaderProgram, bool standaloneShader);
void useProgram();
unsigned getProgramHandle();
+73
View File
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenColorIO Project.
#ifndef INCLUDED_OCIO_METALAPP_H
#define INCLUDED_OCIO_METALAPP_H
#include <OpenColorIO/OpenColorIO.h>
#include "oglapp.h"
namespace OCIO_NAMESPACE
{
struct GraphicsContext;
class MetalBuilder;
typedef OCIO_SHARED_PTR<MetalBuilder> MetalBuilderRcPtr;
class MetalApp;
typedef OCIO_SHARED_PTR<MetalApp> MetalAppRcPtr;
class MtlTexture;
typedef OCIO_SHARED_PTR<MtlTexture> MtlTextureRcPtr;
class MetalApp : public ScreenApp
{
public:
MetalApp() = delete;
MetalApp(const MetalApp &) = delete;
MetalApp & operator=(const MetalApp &) = delete;
// Initialize the app with given window name & client rect size.
MetalApp(const char * winTitle, int winWidth, int winHeight);
virtual ~MetalApp();
void initContext();
// Initialize the image.
void initImage(int imageWidth, int imageHeight,
Components comp, const float * imageBuffer) override;
// Update the image if it changes.
void updateImage(const float * imageBuffer) override;
// Set the shader code.
void setShader(GpuShaderDescRcPtr & shaderDesc) override;
// Prepares and binds the OpenGL state used to present metal output texture in GLUT window
void prepareAndBindOpenGLState();
// Process the image.
void redisplay() override;
// Return a pointer of either ScreenApp or HeadlessApp depending on the
// OCIO_HEADLESS_ENABLED preprocessor.
static MetalAppRcPtr CreateMetalGlApp(const char * winTitle, int winWidth, int winHeight);
protected:
MtlTextureRcPtr m_image { nullptr };
MtlTextureRcPtr m_outputImage { nullptr };
std::unique_ptr<GraphicsContext> m_context { nullptr };
private:
MetalBuilderRcPtr m_metalBuilder;
bool m_glStateBound { false }; // OpenGL state for outputing the metal output texture contents is bound
};
}
#endif // INCLUDED_OCIO_METALAPP_H
+391
View File
@@ -0,0 +1,391 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenColorIO Project.
#include <iostream>
#include <sstream>
#include <utility>
#include <fstream>
#import <Metal/Metal.h>
#import <AppKit/AppKit.h>
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#include <OpenColorIO/OpenColorIO.h>
#include "metalapp.h"
#include "msl.h"
#include "glsl.h"
#include "mtltexture.h"
namespace OCIO_NAMESPACE
{
struct GraphicsContext
{
GraphicsContext() = delete;
GraphicsContext(NSOpenGLContext* glContext, id<MTLDevice> metalDevice)
{
this->glContext = glContext;
this->metalDevice = metalDevice;
}
~GraphicsContext()
{
if(glContext)
[glContext release];
glContext = nil;
}
NSOpenGLContext* glContext;
id<MTLDevice> metalDevice;
};
MetalApp::MetalApp(const char * winTitle, int winWidth, int winHeight)
: ScreenApp(winTitle, winWidth, winHeight)
{
initContext();
}
void MetalApp::initContext()
{
NSOpenGLContext* currentContext = [NSOpenGLContext currentContext];
m_context = std::unique_ptr<GraphicsContext>(new GraphicsContext(currentContext, MTLCreateSystemDefaultDevice()));
}
MetalApp::~MetalApp()
{
m_metalBuilder.reset();
m_glStateBound = false;
}
void MetalApp::initImage(int imgWidth, int imgHeight, Components comp, const float * image)
{
std::vector<float> imageData;
if(comp == Components::COMPONENTS_RGB)
{
RGB_to_RGBA(image, 3 * imgWidth * imgHeight, imageData);
image = imageData.data();
}
setImageDimensions(imgWidth, imgHeight, comp);
m_image = std::make_shared<MtlTexture>(m_context->metalDevice, imgWidth, imgHeight, image);
m_outputImage = std::make_shared<MtlTexture>(m_context->metalDevice, m_context->glContext, imgWidth, imgHeight, image);
m_glStateBound = false;
}
void MetalApp::updateImage(const float *image)
{
std::vector<float> imageData;
if(getImageComponents() == Components::COMPONENTS_RGB)
{
RGB_to_RGBA(image, 3 * m_image->getWidth() * m_image->getHeight(), imageData);
image = imageData.data();
}
m_image->update(image);
}
void MetalApp::prepareAndBindOpenGLState()
{
// A dummyShaderDesc is enough.
// The builder will only be used to build GL program
GpuShaderDescRcPtr dummyShaderDesc = GpuShaderDesc::CreateShaderDesc();
m_oglBuilder = OpenGLBuilder::Create(dummyShaderDesc);
std::ostringstream main;
main << std::endl
<< "uniform sampler2DRect img;" << std::endl
<< std::endl
<< "void main()" << std::endl
<< "{" << std::endl
<< " gl_FragColor = texture2DRect(img, gl_TexCoord[0].st * "
<< "vec2(" << m_outputImage->getWidth() << ", " << m_outputImage->getHeight() << "));"
<< std::endl
<< "}" << std::endl;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, m_outputImage->getGLHandle());
// Build the fragment shader program.
m_oglBuilder->buildProgram(main.str().c_str(), true);
// Enable the fragment shader program, and all needed resources.
m_oglBuilder->useProgram();
// The image texture.
glUniform1i(glGetUniformLocation(m_oglBuilder->getProgramHandle(), "img"), 0);
m_glStateBound = true;
}
void MetalApp::setShader(GpuShaderDescRcPtr & shaderDesc)
{
std::ostringstream main;
m_metalBuilder = MetalBuilder::Create(shaderDesc);
m_metalBuilder->allocateAllTextures(1);
if(shaderDesc->getLanguage() == GPU_LANGUAGE_MSL_2_0)
{
std::ostringstream uniformParams;
std::ostringstream params;
static constexpr char shaderheader[] = { R"(//Metal Shading Language version 2.0
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct VertexOut
{
float4 position [[ position ]];
float2 texCoord0;
};
vertex VertexOut ColorCorrectionVS(unsigned int vId [[ vertex_id ]])
{
VertexOut vOut;
switch(vId)
{
case 0:
vOut.position = float4(-1.0f, 3.0f, 1.0f, 1.0f);
vOut.texCoord0 = float2(0.0f, -1.0f);
break;
case 1:
vOut.position = float4(3.0f, -1.0f, 1.0f, 1.0f);
vOut.texCoord0 = float2(2.0f, 1.0f);
break;
case 2:
vOut.position = float4(-1.0f, -1.0f, 1.0f, 1.0f);
vOut.texCoord0 = float2(0.0f, 1.0f);
break;
};
return vOut;
})" };
main << shaderheader;
main << shaderDesc->getShaderText();
const std::string uniformDataStructName = "UniformData";
const std::string uniformDataInstanceName = "uniformData";
auto uniformLenVariableName = [](std::string varName) -> std::string
{
return varName + "_count";
};
auto uniformDataAccess = [&uniformDataInstanceName](std::string memberName) -> std::string
{
return uniformDataInstanceName + "." + memberName;
};
std::ostringstream uniformData;
std::ostringstream uniformBufferBindings;
const std::string tab = " ";
std::string separator = "";
unsigned int uniformCount = shaderDesc->getNumUniforms();
unsigned int uniformIdx = 1;
for(unsigned int i = 0; i < uniformCount; ++i)
{
GpuShaderDesc::UniformData data;
const char* uniformName = shaderDesc->getUniform(i, data);
std::string spaceSpecifier = ", constant ";
switch(data.m_type)
{
case UNIFORM_DOUBLE:
uniformData << tab << "float " << uniformName << ";\n";
uniformParams << separator << uniformDataAccess(uniformName);
break;
case UNIFORM_BOOL:
uniformData << tab << "int " << uniformName << ";\n";
uniformParams << separator << uniformDataAccess(uniformName);
break;
case UNIFORM_FLOAT3:
uniformData << tab << "float3 " << uniformName << ";\n";
uniformParams << separator << uniformDataAccess(uniformName);
break;
case UNIFORM_VECTOR_FLOAT:
uniformBufferBindings << spaceSpecifier << "float* " << uniformName << "[[ buffer(" << std::to_string(uniformIdx++) << ") ]]\n";
uniformData << tab << "int " << uniformLenVariableName(uniformName) << ";\n";
uniformParams << separator << uniformName << ", " << uniformDataAccess(uniformLenVariableName(uniformName));
break;
case UNIFORM_VECTOR_INT:
uniformBufferBindings << spaceSpecifier << "int* " << uniformName << "[[ buffer(" << std::to_string(uniformIdx++) << ") ]]\n";
uniformData << tab << "int " << uniformLenVariableName(uniformName) << ";\n";
uniformParams << separator << uniformName << ", " << uniformDataAccess(uniformLenVariableName(uniformName));
break;
case UNIFORM_UNKNOWN:
throw Exception("Unknown Uniform type.");
break;
}
separator = ", ";
}
bool needsUniformData = false;
if(uniformData.str().size() > 0)
{
main << "\nstruct " << uniformDataStructName << "\n"
<< "{\n"
<< uniformData.str()
<< "};\n";
needsUniformData = true;
}
main << "\n\n\n"
<<"fragment float4 ColorCorrectionPS(VertexOut in [[stage_in]], texture2d<float> colorIn [[ texture(0) ]]\n";
if(needsUniformData)
{
main << ", constant " << uniformDataStructName << "& " << uniformDataInstanceName
<< " [[ buffer(0) ]]\n";
}
if(uniformBufferBindings.str().size() > 0)
{
main << uniformBufferBindings.str();
}
separator = "";
int tex_slot = 1;
for(unsigned int i = 0; i < shaderDesc->getNum3DTextures(); ++i)
{
const char* textureName;
const char* samplerName;
unsigned int edgeLen;
Interpolation interpolation;
shaderDesc->get3DTexture(i, textureName, samplerName, edgeLen, interpolation);
main << ", texture3d<float> "
<< textureName
<< " [[ texture("
<< std::to_string(tex_slot)
<< ") ]]\n";
main << ", sampler "
<< samplerName
<< " [[ sampler("
<< std::to_string(tex_slot++)
<< ") ]]\n";
params << separator
<< textureName
<< ", "
<< samplerName;
separator = ", ";
}
for(unsigned int i = 0; i < shaderDesc->getNumTextures(); ++i)
{
const char* textureName;
const char* samplerName;
unsigned int width, height;
GpuShaderCreator::TextureType channel;
Interpolation interpolation;
shaderDesc->getTexture(i, textureName, samplerName, width, height, channel, interpolation);
if(height > 1)
{
main << ", texture2d<float> ";
}
else
{
main << ", texture1d<float> ";
}
main << textureName
<< " [[ texture("
<< std::to_string(tex_slot)
<< ") ]]\n";
main << ", sampler "
<< samplerName
<< " [[ sampler("
<< std::to_string(tex_slot++)
<< ") ]]\n";
params << separator
<< textureName
<< ", "
<< samplerName;
separator = ", ";
}
if(uniformParams.str().size() > 0 || params.str().size() > 0)
{
separator = ", ";
}
main << ")"
"{\n"
" constexpr sampler s = sampler(address::clamp_to_edge);\n"
" float4 inPixel = colorIn.sample(s, float2(in.texCoord0.x, in.texCoord0.y));\n"
" return "
<< shaderDesc->getFunctionName() << "(" << params.str() << uniformParams.str() << separator << "inPixel);\n"
<< "}\n";
main << std::endl;
}
else
{
throw Exception("Metal renderer can only consume MSL shaders");
}
if(printShader())
{
std::cout << std::endl;
std::cout << "GPU Shader Program:" << std::endl;
std::cout << std::endl;
std::cout << main.str() << std::endl;
std::cout << std::endl;
}
// Build the fragment shader program.
if(m_metalBuilder->buildPipelineStateObject(main.str().c_str()))
{
m_metalBuilder->applyColorCorrection(m_image->getMetalTextureHandle(),
m_outputImage->getMetalTextureHandle(),
m_outputImage->getWidth(),
m_outputImage->getHeight());
}
}
void MetalApp::redisplay()
{
if(m_metalBuilder)
{
m_metalBuilder->applyColorCorrection(m_image->getMetalTextureHandle(),
m_outputImage->getMetalTextureHandle(),
m_outputImage->getWidth(),
m_outputImage->getHeight());
}
if(!m_glStateBound)
{
prepareAndBindOpenGLState();
}
ScreenApp::redisplay();
}
MetalAppRcPtr MetalApp::CreateMetalGlApp(const char * winTitle, int winWidth, int winHeight)
{
return std::make_shared<MetalApp>(winTitle, winWidth, winHeight);
}
} // namespace OCIO_NAMESPACE
+142
View File
@@ -0,0 +1,142 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenColorIO Project.
#ifndef INCLUDED_OCIO_MSL_H
#define INCLUDED_OCIO_MSL_H
#include <vector>
#include <OpenColorIO/OpenColorIO.h>
#import <Metal/Metal.h>
namespace OCIO_NAMESPACE
{
class MetalBuilder;
typedef OCIO_SHARED_PTR<MetalBuilder> MetalBuilderRcPtr;
void RGB_to_RGBA(const float* lutValues, int valueCount, std::vector<float>& float4AdaptedLutValues);
// This is a reference implementation showing how to do the texture upload & allocation,
// and the program compilation for the GLSL shader language.
class MetalBuilder
{
struct TextureId
{
std::string m_textureName;
id<MTLTexture> m_texture;
std::string m_samplerName;
id<MTLSamplerState> m_samplerState;
MTLTextureType m_type;
TextureId(id<MTLTexture> tex,
const std::string & textureName,
id<MTLSamplerState> samplerState,
const std::string & samplerName,
MTLTextureType type)
: m_textureName(textureName)
, m_texture(tex)
, m_samplerName(samplerName)
, m_samplerState(samplerState)
, m_type(type)
{}
~TextureId()
{
m_texture = nil;
m_samplerState = nil;
}
void release()
{
if(m_texture)
{
[m_texture release];
}
m_texture = nil;
if(m_samplerState)
{
[m_samplerState release];
}
m_samplerState = nil;
}
};
typedef std::vector<TextureId> TextureIds;
// Uniform are used for dynamic parameters.
class Uniform
{
public:
Uniform(const std::string & name, const GpuShaderDesc::UniformData & data);
private:
Uniform() = delete;
std::string m_name;
GpuShaderDesc::UniformData m_data;
};
typedef std::vector<Uniform> Uniforms;
public:
// Create an MSL builder using the GPU shader information from a specific processor
static MetalBuilderRcPtr Create(const GpuShaderDescRcPtr & gpuShader);
~MetalBuilder();
inline void setVerbose(bool verbose) { m_verbose = verbose; }
inline bool isVerbose() const { return m_verbose; }
// Allocate & upload all the needed textures
// (i.e. the index is the first available index for any kind of textures).
void allocateAllTextures(unsigned startIndex);
// Update all uniforms.
void setUniforms(id<MTLRenderCommandEncoder> renderCmdEncoder);
bool buildPipelineStateObject(const std::string & clientShaderProgram);
void applyColorCorrection(id<MTLTexture> inputTexturePtr, id<MTLTexture> outputTexturePtr, unsigned int outWidth, unsigned int outHeight);
// Determine the maximum width value of a texture
// depending of the graphic card and its driver.
static unsigned GetTextureMaxWidth();
id<MTLDevice> getMetalDevice() { return m_device; }
protected:
MetalBuilder(const GpuShaderDescRcPtr & gpuShader);
// Metal Capturing functions -- used for debugging
void triggerProgrammaticCaptureScope();
void stopProgrammaticCaptureScope();
void deleteAllTextures();
// Critical for declaring primitive data types like float2, float3, ...
std::string getMSLHeader();
private:
MetalBuilder();
MetalBuilder(const MetalBuilder &) = delete;
MetalBuilder& operator=(const MetalBuilder &) = delete;
void fillUniformBufferData();
const GpuShaderDescRcPtr m_shaderDesc; // Description of the fragment shader to create
id<MTLDevice> m_device;
id<MTLCommandQueue> m_cmdQueue;
id<MTLLibrary> m_library;
id<MTLRenderPipelineState> m_PSO;
unsigned m_startIndex; // Starting index for texture allocations
TextureIds m_textureIds; // Texture ids of all needed textures
std::vector<uint8_t> m_uniformData; // Uniform buffer Data
std::string m_shaderCacheID; // Current shader program key
bool m_verbose; // Print shader code to std::cout for debugging purposes
};
} // namespace OCIO_NAMESPACE
#endif // INCLUDED_OCIO_MSL_H
+547
View File
@@ -0,0 +1,547 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenColorIO Project.
#include <unordered_map>
#include <string>
#include <sstream>
#include <iostream>
#include <OpenColorIO/OpenColorIO.h>
#include "msl.h"
#include "mtltexture.h"
#import <Metal/Metal.h>
namespace OCIO_NAMESPACE
{
void RGB_to_RGBA(const float* lutValues, int valueCount, std::vector<float>& float4AdaptedLutValues)
{
if(valueCount % 3 != 0)
throw Exception("Value count should be divisible by 3.");
valueCount = valueCount * 4 / 3;
if(lutValues != nullptr)
{
float4AdaptedLutValues.resize(valueCount);
const float *rgbLutValuesIt = lutValues;
float *rgbaLutValuesIt = float4AdaptedLutValues.data();
const float *end = rgbaLutValuesIt + valueCount;
while(rgbaLutValuesIt != end) {
*rgbaLutValuesIt++ = *rgbLutValuesIt++;
*rgbaLutValuesIt++ = *rgbLutValuesIt++;
*rgbaLutValuesIt++ = *rgbLutValuesIt++;
*rgbaLutValuesIt++ = 1.0f;
}
}
}
namespace
{
id<MTLSamplerState> GetSamplerState(id<MTLDevice> device, Interpolation interpolation)
{
MTLSamplerDescriptor* samplerDesc = [MTLSamplerDescriptor new];
if(interpolation==INTERP_NEAREST)
{
[samplerDesc setMinFilter:MTLSamplerMinMagFilterNearest];
[samplerDesc setMagFilter:MTLSamplerMinMagFilterNearest];
}
else
{
[samplerDesc setMinFilter:MTLSamplerMinMagFilterLinear];
[samplerDesc setMagFilter:MTLSamplerMinMagFilterLinear];
}
[samplerDesc setSAddressMode:MTLSamplerAddressModeClampToEdge];
[samplerDesc setTAddressMode:MTLSamplerAddressModeClampToEdge];
[samplerDesc setRAddressMode:MTLSamplerAddressModeClampToEdge];
id<MTLSamplerState> samplerState = [device newSamplerStateWithDescriptor:samplerDesc];
[samplerDesc release];
return samplerState;
}
id<MTLTexture> AllocateTexture3D(id<MTLDevice> device,
unsigned edgelen, const float * lutValues)
{
if(lutValues == nullptr)
{
throw Exception("Missing texture data");
}
// MTLPixelFormatRGB32Float not supported on metal. Adapt to MTLPixelFormatRGBA32Float
std::vector<float> float4AdaptedLutValues;
RGB_to_RGBA(lutValues, 3*edgelen*edgelen*edgelen, float4AdaptedLutValues);
MTLTextureDescriptor* texDescriptor = [MTLTextureDescriptor new];
[texDescriptor setTextureType:MTLTextureType3D];
[texDescriptor setWidth:edgelen];
[texDescriptor setHeight:edgelen];
[texDescriptor setDepth:edgelen];
[texDescriptor setStorageMode:MTLStorageModeManaged];
[texDescriptor setPixelFormat:MTLPixelFormatRGBA32Float];
[texDescriptor setMipmapLevelCount:1];
id<MTLTexture> tex = [device newTextureWithDescriptor:texDescriptor];
const void* texData = float4AdaptedLutValues.data();
[tex replaceRegion:MTLRegionMake3D(0, 0, 0, edgelen, edgelen, edgelen)
mipmapLevel:0
slice:0
withBytes:texData
bytesPerRow:edgelen * 4 * sizeof(float)
bytesPerImage:edgelen * edgelen * 4 * sizeof(float)];
[texDescriptor release];
return tex;
}
id<MTLTexture> AllocateTexture2D(id<MTLDevice> device,
unsigned width, unsigned height,
GpuShaderDesc::TextureType channel,
const float * values)
{
if (values == nullptr)
{
throw Exception("Missing texture data.");
}
const int channelPerPix = channel == GpuShaderCreator::TEXTURE_RED_CHANNEL ? 1 : 4;
std::vector<float> adaptedLutValues;
if(channel == GpuShaderDesc::TEXTURE_RED_CHANNEL)
{
adaptedLutValues.resize(width * height);
memcpy(adaptedLutValues.data(), values, width * height * sizeof(float));
}
else
{
RGB_to_RGBA(values, 3*width*height, adaptedLutValues);
}
MTLTextureDescriptor* texDescriptor = [MTLTextureDescriptor new];
MTLPixelFormat pixelFormat = channel == GpuShaderDesc::TEXTURE_RED_CHANNEL ? MTLPixelFormatR32Float : MTLPixelFormatRGBA32Float;
[texDescriptor setTextureType:height > 1 ? MTLTextureType2D : MTLTextureType1D];
[texDescriptor setWidth:width];
[texDescriptor setHeight:height];
[texDescriptor setDepth:1];
[texDescriptor setStorageMode:MTLStorageModeManaged];
[texDescriptor setPixelFormat:pixelFormat];
[texDescriptor setMipmapLevelCount:1];
id<MTLTexture> tex = [device newTextureWithDescriptor:texDescriptor];
[tex replaceRegion:MTLRegionMake3D(0, 0, 0, width, height, 1)
mipmapLevel:0
withBytes:adaptedLutValues.data()
bytesPerRow:channelPerPix * width * sizeof(float)];
[texDescriptor release];
return tex;
}
}
//////////////////////////////////////////////////////////
MetalBuilder::Uniform::Uniform(const std::string & name, const GpuShaderDesc::UniformData & data)
: m_name(name)
, m_data(data)
{
}
//////////////////////////////////////////////////////////
MetalBuilderRcPtr MetalBuilder::Create(const GpuShaderDescRcPtr & shaderDesc)
{
return MetalBuilderRcPtr(new MetalBuilder(shaderDesc));
}
MetalBuilder::MetalBuilder(const GpuShaderDescRcPtr & shaderDesc)
: m_shaderDesc(shaderDesc)
, m_startIndex(0)
, m_textureIds{}
, m_uniformData{}
, m_verbose(false)
{
m_device = MTLCreateSystemDefaultDevice();
m_cmdQueue = [m_device newCommandQueue];
}
MetalBuilder::~MetalBuilder()
{
if(m_cmdQueue)
{
[m_cmdQueue release];
}
m_cmdQueue = nil;
if(m_PSO)
{
[m_PSO release];
}
m_PSO = nil;
deleteAllTextures();
}
void MetalBuilder::allocateAllTextures(unsigned startIndex)
{
deleteAllTextures();
// This is the first available index for the textures.
m_startIndex = startIndex;
unsigned currIndex = m_startIndex;
// Process the 3D LUT first.
const unsigned maxTexture3D = m_shaderDesc->getNum3DTextures();
for(unsigned idx=0; idx<maxTexture3D; ++idx)
{
// 1. Get the information of the 3D LUT.
const char * textureName = nullptr;
const char * samplerName = nullptr;
unsigned edgelen = 0;
Interpolation interpolation = INTERP_LINEAR;
m_shaderDesc->get3DTexture(idx, textureName, samplerName, edgelen, interpolation);
if(!textureName || !*textureName
|| !samplerName || !*samplerName
|| edgelen==0)
{
throw Exception("The texture data is corrupted");
}
const float * values = nullptr;
m_shaderDesc->get3DTextureValues(idx, values);
if(!values)
{
throw Exception("The texture values are missing");
}
// 2. Allocate the 3D LUT.
id<MTLTexture> texture = AllocateTexture3D(m_device, edgelen, values);
id<MTLSamplerState> samplerState = GetSamplerState(m_device, interpolation);
// 3. Keep the texture id & name for the later enabling.
m_textureIds.push_back(TextureId(texture, textureName, samplerState, samplerName, MTLTextureType3D));
currIndex++;
}
// Process the 1D LUTs.
const unsigned maxTexture2D = m_shaderDesc->getNumTextures();
for(unsigned idx=0; idx<maxTexture2D; ++idx)
{
// 1. Get the information of the 1D LUT.
const char * textureName = nullptr;
const char * samplerName = nullptr;
unsigned width = 0;
unsigned height = 0;
GpuShaderDesc::TextureType channel = GpuShaderDesc::TEXTURE_RGB_CHANNEL;
Interpolation interpolation = INTERP_LINEAR;
m_shaderDesc->getTexture(idx, textureName, samplerName, width, height, channel, interpolation);
if (!textureName || !*textureName
|| !samplerName || !*samplerName
|| width==0)
{
throw Exception("The texture data is corrupted");
}
const float * values = 0x0;
m_shaderDesc->getTextureValues(idx, values);
if(!values)
{
throw Exception("The texture values are missing");
}
// 2. Allocate the 1D LUT (a 2D texture is needed to hold large LUTs).
id<MTLTexture> texture = AllocateTexture2D(m_device, width, height, channel, values);
id<MTLSamplerState> samplerState = GetSamplerState(m_device, interpolation);
// 3. Keep the texture id & name for the later enabling.
MTLTextureType type = (height > 1) ? MTLTextureType2D : MTLTextureType1D;
m_textureIds.push_back(TextureId(texture, textureName, samplerState, samplerName, type));
currIndex++;
}
}
void MetalBuilder::deleteAllTextures()
{
for(auto& textureId : m_textureIds)
{
if(textureId.m_texture)
{
textureId.release();
}
}
m_textureIds.clear();
}
void MetalBuilder::fillUniformBufferData()
{
m_uniformData.clear();
m_uniformData.reserve(1024);
const unsigned maxUniforms = m_shaderDesc->getNumUniforms();
int alignment = 4;
for (unsigned idx = 0; idx < maxUniforms; ++idx)
{
GpuShaderDesc::UniformData data;
m_shaderDesc->getUniform(idx, data);
switch(data.m_type)
{
case UNIFORM_BOOL:
{
float v = data.m_getBool() == false ? 0.0f : 1.0f;
size_t offset = m_uniformData.size();
size_t dataSize = sizeof(float);
m_uniformData.resize(offset + dataSize);
memcpy(&m_uniformData[offset], &v, dataSize);
alignment = std::max(alignment, 4);
}
break;
case UNIFORM_DOUBLE:
{
float v = data.m_getDouble();
size_t offset = m_uniformData.size();
size_t dataSize = sizeof(float);
m_uniformData.resize(offset + dataSize);
memcpy(&m_uniformData[offset], &v, dataSize);
alignment = std::max(alignment, 4);
}
break;
case UNIFORM_FLOAT3:
{
const float* v = data.m_getFloat3().data();
size_t offset = m_uniformData.size();
size_t dataSize = 3 * sizeof(float);
m_uniformData.resize(offset + 4 * sizeof(float));
memcpy(&m_uniformData[offset], v, dataSize);
alignment = std::max(alignment, 16);
}
break;
case UNIFORM_VECTOR_INT:
{
const int v = data.m_vectorInt.m_getSize();
size_t offset = m_uniformData.size();
size_t dataSize = sizeof(int);
m_uniformData.resize(offset + dataSize);
memcpy(&m_uniformData[offset], &v, dataSize);
alignment = std::max(alignment, 4);
}
break;
case UNIFORM_VECTOR_FLOAT:
{
const int v = data.m_vectorFloat.m_getSize();
size_t offset = m_uniformData.size();
size_t dataSize = sizeof(int);
m_uniformData.resize(offset + dataSize);
memcpy(&m_uniformData[offset], &v, dataSize);
alignment = std::max(alignment, 4);
}
break;
case UNIFORM_UNKNOWN:
throw Exception("Unknown uniform type.");
};
}
m_uniformData.resize(((m_uniformData.size() + alignment - 1) / alignment) * alignment);
}
void MetalBuilder::setUniforms(id<MTLRenderCommandEncoder> renderCmdEncoder)
{
fillUniformBufferData();
if(m_uniformData.size() > 0)
[renderCmdEncoder setFragmentBytes:m_uniformData.data() length:m_uniformData.size() atIndex:0];
const unsigned maxUniforms = m_shaderDesc->getNumUniforms();
int uniformId = 1;
for (unsigned idx = 0; idx < maxUniforms; ++idx)
{
GpuShaderDesc::UniformData data;
m_shaderDesc->getUniform(idx, data);
switch(data.m_type)
{
case UNIFORM_BOOL:
case UNIFORM_DOUBLE:
case UNIFORM_FLOAT3:
// Part of uniform data buffer
break;
case UNIFORM_VECTOR_INT:
{
int size = data.m_vectorInt.m_getSize();
const int dummyInt = 123456789;
const int* v = size == 0 ? &dummyInt : data.m_vectorInt.m_getVector();
size = size == 0 ? sizeof(int) : size * sizeof(int);
[renderCmdEncoder setFragmentBytes:v length:size * sizeof(int) atIndex:uniformId++];
}
break;
case UNIFORM_VECTOR_FLOAT:
{
int size = data.m_vectorFloat.m_getSize();
const float dummyFloat = 123456789.0f;
const float* v = size == 0 ? &dummyFloat : data.m_vectorFloat.m_getVector();
size = size == 0 ? sizeof(float) : size * sizeof(float);
[renderCmdEncoder setFragmentBytes:v length:size atIndex:uniformId++];
}
break;
case UNIFORM_UNKNOWN:
throw Exception("Unknown uniform type.");
};
}
}
bool MetalBuilder::buildPipelineStateObject(const std::string & clientShaderProgram)
{
NSString* shaderSrc = [NSString stringWithUTF8String:clientShaderProgram.c_str()];
NSError* error = nil;
MTLCompileOptions* options = [MTLCompileOptions new];
[options setLanguageVersion:MTLLanguageVersion2_0];
[options setFastMathEnabled:NO];
@autoreleasepool
{
m_library = [[m_device newLibraryWithSource:shaderSrc options:options error:&error] autorelease];
id<MTLFunction> vertexShader = [[m_library newFunctionWithName:@"ColorCorrectionVS"] autorelease];
id<MTLFunction> pixelShader = [[m_library newFunctionWithName:@"ColorCorrectionPS"] autorelease];
MTLRenderPipelineDescriptor* renderPipelineDesc = [[MTLRenderPipelineDescriptor new] autorelease];
[renderPipelineDesc setVertexFunction:vertexShader];
[renderPipelineDesc setFragmentFunction:pixelShader];
[renderPipelineDesc setVertexDescriptor:nil];
[renderPipelineDesc setRasterizationEnabled:YES];
[renderPipelineDesc setInputPrimitiveTopology:MTLPrimitiveTopologyClassTriangle];
[[renderPipelineDesc colorAttachments][0] setPixelFormat:MTLPixelFormatRGBA32Float];
m_PSO = [m_device newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&error];
}
if(error != nil)
{
throw Exception("Failed to create pipeline state object. Applying color transformation is not possible.");
}
return true;
}
void MetalBuilder::triggerProgrammaticCaptureScope()
{
if (@available(macOS 10.15, *))
{
MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager];
MTLCaptureDescriptor* captureDescriptor = [[MTLCaptureDescriptor alloc] init];
captureDescriptor.captureObject = m_device;
NSError *error;
if (![captureManager startCaptureWithDescriptor:captureDescriptor error:&error])
{
NSLog(@"Failed to start capture, error %@", error);
}
}
else
{
NSLog(@"Capturing functionality is only available on MacOS 10.15 and above.");
}
}
void MetalBuilder::stopProgrammaticCaptureScope()
{
if (@available(macOS 10.15, *))
{
MTLCaptureManager* captureManager = [MTLCaptureManager sharedCaptureManager];
[captureManager stopCapture];
}
}
void MetalBuilder::applyColorCorrection(id<MTLTexture> inputTexture, id<MTLTexture> outputTexture, unsigned int outWidth, unsigned int outHeight)
{
static bool captureThisFrame = false;
if(captureThisFrame)
{
triggerProgrammaticCaptureScope();
}
id<MTLCommandBuffer> cmdBuffer = [m_cmdQueue commandBuffer];
MTLRenderPassDescriptor* renderPassDesc = [MTLRenderPassDescriptor new];
if (@available(macOS 10.15, *)) {
[renderPassDesc setRenderTargetWidth:outWidth];
[renderPassDesc setRenderTargetHeight:outHeight];
}
else
{
throw Exception("Metal Renderer Only Operates on MacOS 10.15 and above.");
}
[[renderPassDesc colorAttachments][0] setTexture:outputTexture];
[[renderPassDesc colorAttachments][0] setLoadAction:MTLLoadActionClear];
[[renderPassDesc colorAttachments][0] setStoreAction:MTLStoreActionStore];
id<MTLRenderCommandEncoder> renderCmdEncoder = [cmdBuffer renderCommandEncoderWithDescriptor:renderPassDesc];
[renderCmdEncoder setRenderPipelineState:m_PSO];
[renderCmdEncoder setFragmentTexture:inputTexture atIndex:0];
setUniforms(renderCmdEncoder);
const size_t max = m_textureIds.size();
for (size_t idx=0; idx<max; ++idx)
{
const TextureId& data = m_textureIds[idx];
[renderCmdEncoder setFragmentTexture:data.m_texture atIndex:(m_startIndex + idx)];
[renderCmdEncoder setFragmentSamplerState:data.m_samplerState atIndex:(m_startIndex + idx)];
}
[renderCmdEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
[renderCmdEncoder endEncoding];
[cmdBuffer commit];
[cmdBuffer waitUntilCompleted];
[renderPassDesc release];
if(captureThisFrame)
{
stopProgrammaticCaptureScope();
}
}
unsigned MetalBuilder::GetTextureMaxWidth()
{
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
if ([device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1] ||
[device supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v2])
{
return 8192;
}
return 16384;
}
} // namespace OCIO_NAMESPACE
+84
View File
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenColorIO Project.
#ifndef INCLUDED_OCIO_MTLTEXTURE_H
#define INCLUDED_OCIO_MTLTEXTURE_H
#include <vector>
#include <OpenGL/gl.h>
#import <AppKit/AppKit.h>
#import <Metal/Metal.h>
#import <CoreVideo/CVPixelBuffer.h>
#import <CoreVideo/CVOpenGLTextureCache.h>
#import <CoreVideo/CVMetalTextureCache.h>
#include <OpenColorIO/OpenColorIO.h>
namespace OCIO_NAMESPACE
{
typedef struct {
int cvPixelFormat;
MTLPixelFormat mtlFormat;
GLuint glInternalFormat;
GLuint glFormat;
GLuint glType;
} GLMetalTextureFormatInfo;
class MtlTexture
{
public:
MtlTexture() = delete;
MtlTexture(const MtlTexture&) = delete;
MtlTexture & operator=(const MtlTexture&) = delete;
int getWidth() const { return m_width; }
int getHeight() const { return m_height; }
uint64_t getGLHandle() const
{
if(!m_openGLContext)
{
throw Exception("There is no valid OpenGL Context for this texture");
}
return m_texID;
}
~MtlTexture();
MtlTexture(id<MTLDevice> device, uint32_t width, uint32_t height, const float* image);
MtlTexture(id<MTLDevice> device, NSOpenGLContext* glContext, uint32_t width, uint32_t height, const float* image);
void update(const float* image);
id<MTLTexture> getMetalTextureHandle() const { return m_metalTexture; }
std::vector<float> readTexture() const;
private:
void createGLTexture();
void createMetalTexture();
id<MTLDevice> m_device;
NSOpenGLContext* m_openGLContext;
int m_width;
int m_height;
unsigned int m_texID;
id<MTLTexture> m_metalTexture;
const GLMetalTextureFormatInfo* m_formatInfo;
CVPixelBufferRef m_CVPixelBuffer;
CVMetalTextureRef m_CVMTLTexture;
CVOpenGLTextureCacheRef m_CVGLTextureCache;
CVOpenGLTextureRef m_CVGLTexture;
CGLPixelFormatObj m_CGLPixelFormat;
// Metal
CVMetalTextureCacheRef m_CVMTLTextureCache;
};
} // namespace OCIO_NAMESPACE
#endif // INCLUDED_OCIO_MTLTEXTURE_H
+211
View File
@@ -0,0 +1,211 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenColorIO Project.
#include <vector>
#include "msl.h"
#include "mtltexture.h"
namespace OCIO_NAMESPACE
{
// Table of equivalent formats across CoreVideo, Metal, and OpenGL
static const GLMetalTextureFormatInfo GLMetalInteropFormatTable[] =
{
// Core Video Pixel Format,Metal Pixel Format, GL internalformat, GL format, GL type
{ kCVPixelFormatType_32BGRA, MTLPixelFormatBGRA8Unorm, GL_RGBA,
GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV },
{ kCVPixelFormatType_ARGB2101010LEPacked, MTLPixelFormatBGR10A2Unorm, GL_RGB10_A2,
GL_BGRA, GL_UNSIGNED_INT_2_10_10_10_REV },
{ kCVPixelFormatType_32BGRA, MTLPixelFormatBGRA8Unorm_sRGB, GL_SRGB8_ALPHA8,
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV },
{ kCVPixelFormatType_64RGBAHalf, MTLPixelFormatRGBA16Float, GL_RGBA,
GL_RGBA, GL_HALF_FLOAT },
{ kCVPixelFormatType_128RGBAFloat, MTLPixelFormatRGBA32Float, GL_RGBA,
GL_RGBA, GL_FLOAT},
};
const GLMetalTextureFormatInfo* textureFormatInfoFromMetalPixelFormat(MTLPixelFormat pixelFormat)
{
const int numInteropFormats =
sizeof(GLMetalInteropFormatTable) / sizeof(GLMetalInteropFormatTable[0]);
for(int i = 0; i < numInteropFormats; i++) {
if(pixelFormat == GLMetalInteropFormatTable[i].mtlFormat)
{
return &GLMetalInteropFormatTable[i];
}
}
return NULL;
}
MtlTexture::MtlTexture(id<MTLDevice> device, uint32_t width, uint32_t height, const float* image)
: m_width(width), m_height(height)
{
m_device = device;
m_openGLContext = nullptr;
MTLTextureDescriptor* texDescriptor = [MTLTextureDescriptor new];
const int channelPerPix = 4;
MTLPixelFormat pixelFormat = MTLPixelFormatRGBA32Float;
[texDescriptor setWidth:width];
[texDescriptor setHeight:height];
[texDescriptor setDepth:1];
[texDescriptor setStorageMode:MTLStorageModeManaged];
[texDescriptor setPixelFormat:pixelFormat];
[texDescriptor setMipmapLevelCount:1];
m_metalTexture = [device newTextureWithDescriptor:texDescriptor];
if(image)
{
[m_metalTexture replaceRegion:MTLRegionMake3D(0, 0, 0, width, height, 1)
mipmapLevel:0
withBytes:image
bytesPerRow:channelPerPix * width * sizeof(float)];
}
[texDescriptor release];
}
MtlTexture::MtlTexture(id<MTLDevice> device,
NSOpenGLContext* glContext,
uint32_t width, uint32_t height,
const float* image) : m_width(width), m_height(height)
{
NSDictionary* cvBufferProperties = @{
(__bridge NSString*)kCVPixelBufferOpenGLCompatibilityKey : @YES,
(__bridge NSString*)kCVPixelBufferMetalCompatibilityKey : @YES,
};
m_device = device;
m_openGLContext = glContext;
m_formatInfo = textureFormatInfoFromMetalPixelFormat(MTLPixelFormatRGBA32Float);
CVReturn cvret = CVPixelBufferCreate(kCFAllocatorDefault,
m_width, m_height,
m_formatInfo->cvPixelFormat,
(__bridge CFDictionaryRef)cvBufferProperties,
&m_CVPixelBuffer);
if(cvret != kCVReturnSuccess)
{
throw Exception("Cannot create Pixel Buffer");
}
m_CGLPixelFormat = m_openGLContext.pixelFormat.CGLPixelFormatObj;
createGLTexture();
createMetalTexture();
if(image != nullptr)
{
update(image);
}
}
void MtlTexture::createGLTexture()
{
CVReturn cvret;
// Create an OpenGL CoreVideo texture cache from the pixel buffer.
cvret = CVOpenGLTextureCacheCreate(
kCFAllocatorDefault,
nil,
m_openGLContext.CGLContextObj,
m_CGLPixelFormat,
nil,
&m_CVGLTextureCache);
if(cvret != kCVReturnSuccess)
{
throw Exception("Failed to create OpenGL Texture Cache");
}
// Create a CVPixelBuffer-backed OpenGL texture image from the texture cache.
cvret = CVOpenGLTextureCacheCreateTextureFromImage(
kCFAllocatorDefault,
m_CVGLTextureCache,
m_CVPixelBuffer,
nil,
&m_CVGLTexture);
if(cvret != kCVReturnSuccess)
{
throw Exception("Failed to create OpenGL Texture From Image");
}
// Get an OpenGL texture name from the CVPixelBuffer-backed OpenGL texture image.
m_texID = CVOpenGLTextureGetName(m_CVGLTexture);
}
void MtlTexture::createMetalTexture()
{
CVReturn cvret;
// Create a Metal Core Video texture cache from the pixel buffer.
cvret = CVMetalTextureCacheCreate(
kCFAllocatorDefault,
nil,
m_device,
nil,
&m_CVMTLTextureCache);
if(cvret != kCVReturnSuccess)
{
throw Exception("Failed to create Metal texture cache");
}
// Create a CoreVideo pixel buffer backed Metal texture image from the texture cache
cvret = CVMetalTextureCacheCreateTextureFromImage(
kCFAllocatorDefault,
m_CVMTLTextureCache,
m_CVPixelBuffer, nil,
m_formatInfo->mtlFormat,
m_width, m_height,
0,
&m_CVMTLTexture);
if(cvret != kCVReturnSuccess)
{
throw Exception("Failed to create CoreVideo Metal texture from image");
}
// Get a Metal texture using the CoreVideo Metal texture reference.
m_metalTexture = CVMetalTextureGetTexture(m_CVMTLTexture);
if(!m_metalTexture)
{
throw Exception("Failed to create Metal texture CoreVideo Metal Texture");
}
}
void MtlTexture::update(const float* image)
{
[m_metalTexture replaceRegion:MTLRegionMake2D(0, 0, m_width, m_height)
mipmapLevel:0
withBytes:image
bytesPerRow:m_width * 4 * sizeof(float)];
}
std::vector<float> MtlTexture::readTexture() const
{
CVPixelBufferLockBaseAddress(m_CVPixelBuffer, 0);
size_t dataSize = CVPixelBufferGetDataSize(m_CVPixelBuffer);
float* data = (float*)CVPixelBufferGetBaseAddress(m_CVPixelBuffer);//(m_CVPixelBuffer, 0);
std::vector<float> img(4 * m_width * m_height);
if((img.size()*sizeof(float)) < dataSize)
{
throw Exception("CPU-side vector is not large enough to read the texture back.");
}
memcpy(img.data(), data, dataSize);
CVPixelBufferUnlockBaseAddress(m_CVPixelBuffer, 0);
return img;
}
MtlTexture::~MtlTexture()
{
if(m_openGLContext)
[m_openGLContext release];
}
}
+7 -2
View File
@@ -43,7 +43,7 @@ OglApp::~OglApp()
m_oglBuilder.reset();
}
void OglApp::initImage(int imgWidth, int imgHeight, Components comp, const float * image)
void OglApp::setImageDimensions(int imgWidth, int imgHeight, Components comp)
{
m_imageWidth = imgWidth;
m_imageHeight = imgHeight;
@@ -52,7 +52,12 @@ void OglApp::initImage(int imgWidth, int imgHeight, Components comp, const float
{
m_imageAspect = (float)m_imageWidth / (float)m_imageHeight;
}
}
void OglApp::initImage(int imgWidth, int imgHeight, Components comp, const float * image)
{
setImageDimensions(imgWidth, imgHeight, comp);
glGenTextures(1, &m_imageTexID);
glActiveTexture(GL_TEXTURE0);
updateImage(image);
@@ -210,7 +215,7 @@ void OglApp::setShader(GpuShaderDescRcPtr & shaderDesc)
<< "}" << std::endl;
// Build the fragment shader program.
m_oglBuilder->buildProgram(main.str().c_str());
m_oglBuilder->buildProgram(main.str().c_str(), false);
// Enable the fragment shader program, and all needed resources.
m_oglBuilder->useProgram();
+12 -7
View File
@@ -87,16 +87,16 @@ public:
};
// Initialize the image.
void initImage(int imageWidth, int imageHeight,
Components comp, const float * imageBuffer);
virtual void initImage(int imageWidth, int imageHeight,
Components comp, const float * imageBuffer);
// Update the image if it changes.
void updateImage(const float * imageBuffer);
virtual void updateImage(const float * imageBuffer);
// Create GL frame and rendering buffers. Needed if readImage will be used.
void createGLBuffers();
// Set the shader code.
void setShader(GpuShaderDescRcPtr & shaderDesc);
virtual void setShader(GpuShaderDescRcPtr & shaderDesc);
// Update the size of the buffer of the OpenGL viewport that will be used to process the image
// (it does not modify the UI). To be called at least one time. Use image size if we want to
@@ -110,7 +110,7 @@ public:
// Read the image from the rendering buffer. It is not meant to be used by interactive
// applications used to display the image.
void readImage(float * imageBuffer);
virtual void readImage(float * imageBuffer);
// Helper to print GL info.
void virtual printGLInfo() const noexcept;
@@ -130,7 +130,14 @@ protected:
// Initialize the OpenGL engine, and set up GLEW if needed.
void setupCommon();
void setImageDimensions(int imgWidth, int imgHeight, Components comp);
Components getImageComponents() const { return m_components; }
bool printShader() const { return m_printShader; }
OpenGLBuilderRcPtr m_oglBuilder;
private:
// Keep track of the original image ratio.
float m_imageAspect{ 1.0f };
@@ -146,8 +153,6 @@ private:
int m_imageHeight{ 0 };
Components m_components{ COMPONENTS_RGBA };
unsigned int m_imageTexID;
OpenGLBuilderRcPtr m_oglBuilder;
};
class ScreenApp: public OglApp
+3 -4
View File
@@ -31,15 +31,14 @@ target_link_libraries(oiiohelpers
PRIVATE
OpenColorIO
${OCIO_HALF_LIB}
utils::strings
)
install(TARGETS oiiohelpers
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/oiiohelpers.h
DESTINATION include/OpenColorIO/oiiohelpers
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/OpenColorIO/oiiohelpers
)
-1
View File
@@ -6,7 +6,6 @@
#include "oiiohelpers.h"
#include "utils/Half.h"
#include "utils/StringUtils.h"
+9
View File
@@ -15,3 +15,12 @@ configure_file("Half.h.in" "Half.h" @ONLY)
set_property(TARGET ${OCIO_HALF_LIB} APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/.."
)
# from_chars shim (via strtod_l)
add_library(utils::from_chars INTERFACE IMPORTED GLOBAL)
set_target_properties(utils::from_chars PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/.."
)
+166
View File
@@ -0,0 +1,166 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenColorIO Project.
#ifndef INCLUDED_NUMBERUTILS_H
#define INCLUDED_NUMBERUTILS_H
#if defined(_MSC_VER)
#define really_inline __forceinline
#else
#define really_inline inline __attribute__((always_inline))
#endif
#include <cstdlib>
#include <locale>
#include <system_error>
#include <type_traits>
namespace OCIO_NAMESPACE
{
namespace NumberUtils
{
struct Locale
{
#ifdef _WIN32
Locale() : local(_create_locale(LC_ALL, "C"))
{
}
~Locale()
{
_free_locale(local);
}
_locale_t local;
#else
Locale() : local(newlocale(LC_ALL_MASK, "C", NULL))
{
}
~Locale()
{
freelocale(local);
}
locale_t local;
#endif
};
struct from_chars_result
{
const char *ptr;
std::errc ec;
};
static const Locale loc;
really_inline from_chars_result from_chars(const char *first, const char *last, double &value) noexcept
{
errno = 0;
if (!first || !last || first == last)
{
return {first, std::errc::invalid_argument};
}
char * endptr = nullptr;
double
#ifdef _WIN32
tempval = _strtod_l(first, &endptr, loc.local);
#else
tempval = ::strtod_l(first, &endptr, loc.local);
#endif
if (errno != 0)
{
return {first + (endptr - first), std::errc::result_out_of_range};
}
else if (endptr == first)
{
return {first, std::errc::invalid_argument};
}
else if (endptr <= last)
{
value = tempval;
return {first + (endptr - first), {}};
}
else
{
return {first, std::errc::argument_out_of_domain};
}
}
really_inline from_chars_result from_chars(const char *first, const char *last, float &value) noexcept
{
errno = 0;
if (!first || !last || first == last)
{
return {first, std::errc::invalid_argument};
}
char *endptr = nullptr;
float
#ifdef _WIN32
tempval = _strtof_l(first, &endptr, loc.local);
#elif __APPLE__
// On OSX, strtod_l is for some reason drastically faster than strtof_l.
tempval = static_cast<float>(::strtod_l(first, &endptr, loc.local));
#else
tempval = ::strtof_l(first, &endptr, loc.local);
#endif
if (errno != 0)
{
return {first + (endptr - first), std::errc::result_out_of_range};
}
else if (endptr == first)
{
return {first, std::errc::invalid_argument};
}
else if (endptr <= last)
{
value = tempval;
return {first + (endptr - first), {}};
}
else
{
return {first, std::errc::argument_out_of_domain};
}
}
really_inline from_chars_result from_chars(const char *first, const char *last, long int &value) noexcept
{
errno = 0;
if (!first || !last || first == last)
{
return {first, std::errc::invalid_argument};
}
char *endptr = nullptr;
long int
#ifdef _WIN32
tempval = _strtol_l(first, &endptr, 0, loc.local);
#else
tempval = ::strtol_l(first, &endptr, 0, loc.local);
#endif
if (errno != 0)
{
return {first + (endptr - first), std::errc::result_out_of_range};
}
else if (endptr == first)
{
return {first, std::errc::invalid_argument};
}
else if (endptr <= last)
{
value = tempval;
return {first + (endptr - first), {}};
}
else
{
return {first, std::errc::argument_out_of_domain};
}
}
} // namespace NumberUtils
} // namespace OCIO_NAMESPACE
#endif // INCLUDED_NUMBERUTILS_H
+13 -24
View File
@@ -7,8 +7,7 @@ if(OCIO_BUILD_TESTS OR OCIO_BUILD_GPU_TESTS OR OCIO_BUILD_PYTHON)
endif()
if(OCIO_BUILD_TESTS)
# Test order is from low-level (i.e. no dependencies)
# to high-level layers.
# Test order is from low-level (i.e. no dependencies) to high-level layers.
add_subdirectory(testutils)
add_subdirectory(utils)
add_subdirectory(cpu)
@@ -19,31 +18,21 @@ if(OCIO_BUILD_GPU_TESTS)
add_subdirectory(gpu)
endif()
if(TARGET OpenImageIO::OpenImageIO)
# Running the OSL unit tests requires OSL which imposes OIIO and Imath.
# OpenShadingLanguage
# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
find_package(OpenShadingLanguage 1.11)
if(NOT OSL_FOUND)
message(WARNING "Could NOT find OpenShadingLanguage. Skipping build the OSL unit tests")
endif()
if(OCIO_USE_OPENEXR_HALF)
# Imath
# https://github.com/AcademySoftwareFoundation/Imath
find_package(Imath 3)
if(NOT Imath_FOUND)
message(WARNING "Could NOT find Imath. Skipping build the OSL unit tests")
if(OpenImageIO_FOUND AND TARGET OpenImageIO::OpenImageIO)
if(TARGET Imath::Imath)
# OpenShadingLanguage
# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage
find_package(OpenShadingLanguage 1.11)
if(OSL_FOUND)
add_subdirectory(osl)
else()
message(WARNING "Could NOT find OpenShadingLanguage. Skipping build of the OSL unit tests")
endif()
endif()
if(OSL_FOUND AND Imath_FOUND)
add_subdirectory(osl)
else()
message(WARNING "Could NOT find Imath. Skipping build of the OSL unit tests")
endif()
else()
message(WARNING "Could NOT find OpenImageIO. Skipping build the OSL unit tests")
message(WARNING "Could NOT find OpenImageIO. Skipping build of the OSL unit tests")
endif()
if(OCIO_BUILD_JAVA)
+12 -5
View File
@@ -11,12 +11,10 @@ function(add_ocio_test NAME SOURCES PRIVATE_INCLUDES)
target_compile_definitions(${TEST_BINARY}
PRIVATE
OpenColorIO_SKIP_IMPORTS
)
target_link_libraries(${TEST_BINARY}
PUBLIC
OpenColorIOHeaders
PRIVATE
OpenColorIO
expat::expat
${OCIO_HALF_LIB}
pystring::pystring
@@ -39,7 +37,6 @@ function(add_ocio_test NAME SOURCES PRIVATE_INCLUDES)
if(PRIVATE_INCLUDES)
target_include_directories(${TEST_BINARY}
PRIVATE
"${CMAKE_SOURCE_DIR}/src/OpenColorIO"
"${CMAKE_SOURCE_DIR}/tests/cpu"
)
endif(PRIVATE_INCLUDES)
@@ -56,11 +53,20 @@ function(add_ocio_test NAME SOURCES PRIVATE_INCLUDES)
PRIVATE
XML_STATIC
)
if (OCIO_USE_WINDOWS_UNICODE)
# Add Unicode definitions to use Unicode functions
target_compile_definitions(${TEST_BINARY}
PRIVATE
UNICODE
_UNICODE
)
endif()
endif(WIN32)
set_target_properties(${TEST_BINARY} PROPERTIES
COMPILE_FLAGS "${PLATFORM_COMPILE_FLAGS}")
add_test(${TEST_NAME} ${TEST_BINARY})
add_test(NAME ${TEST_NAME} COMMAND ${TEST_BINARY})
endfunction(add_ocio_test)
# Eventually we will factor out each test into it's own executable
@@ -77,6 +83,7 @@ set(SOURCES
fileformats/xmlutils/XMLWriterUtils.cpp
GPUProcessor.cpp
GpuShaderDesc.cpp
GpuShaderClassWrapper.cpp
HashUtils.cpp
ImageDesc.cpp
ImagePacking.cpp
+161 -4
View File
@@ -1433,9 +1433,97 @@ OCIO_ADD_TEST(Config, context_variable_with_display_view)
}
}
OCIO_ADD_TEST(Config, context_variable_with_search_path)
OCIO_ADD_TEST(Config, context_variable_with_search_path_v1)
{
// Test a search_path pointing to a context variable.
// Test a search_path containing a context variable for a v1 config file.
// Note: The config validation does not check the path existence, it checks only if the path can
// be successfully resolved. But the processor creation needs to have at least one existing path.
// That's why the tests below check for the config validation and the processor creation.
static const std::string CONFIG =
"ocio_profile_version: 1\n"
"\n"
"search_path: $ENV1\n"
"\n"
"roles:\n"
" default: cs1\n"
" reference: cs1\n"
"\n"
"displays:\n"
" disp1:\n"
" - !<View> {name: view1, colorspace: cs2}\n"
"\n"
"colorspaces:\n"
" - !<ColorSpace>\n"
" name: cs1\n"
"\n"
" - !<ColorSpace>\n"
" name: cs2\n"
" from_reference: !<FileTransform> {src: lut1d_green.ctf}\n";
std::istringstream iss;
iss.str(CONFIG);
// $ENV1 is missing.
OCIO::ConfigRcPtr cfg;
OCIO_CHECK_NO_THROW(cfg = OCIO::Config::CreateFromStream(iss)->createEditableCopy());
OCIO_CHECK_THROW_WHAT(cfg->validate(), OCIO::Exception,
"The search_path '$ENV1' cannot be resolved.");
#ifdef _WIN32
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: '$ENV1\\lut1d_green.ctf'.");
#else
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: '$ENV1/lut1d_green.ctf'.");
#endif
// $ENV1 now exists.
OCIO_CHECK_NO_THROW(cfg->addEnvironmentVar("ENV1", OCIO::GetTestFilesDir().c_str()));
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
// $ENV1 is faulty.
OCIO_CHECK_NO_THROW(cfg->addEnvironmentVar("ENV1", "faulty/path"));
OCIO_CHECK_NO_THROW(cfg->validate()); // Success because there is at least one resolved path.
#ifdef _WIN32
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: 'faulty\\path\\lut1d_green.ctf'.");
#else
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: 'faulty/path/lut1d_green.ctf'.");
#endif
OCIO_CHECK_NO_THROW(cfg->addEnvironmentVar("ENV1", nullptr));
{
// Change the search_path to have at least one successful path i.e. the first one.
const std::string searchPath = OCIO::GetTestFilesDir() + ":$ENV1";
OCIO_CHECK_NO_THROW(cfg->setSearchPath(searchPath.c_str()));
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
}
{
// Change the search_path to have at least one successful path i.e. the second one.
const std::string searchPath = "$ENV1:" + OCIO::GetTestFilesDir();
OCIO_CHECK_NO_THROW(cfg->setSearchPath(searchPath.c_str()));
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
}
}
OCIO_ADD_TEST(Config, context_variable_with_search_path_v2)
{
// Test a search_path containing a context variable for a v2 config file.
// Note: The config validation does not check the path existence, it checks only if the path can
// be successfully resolved. But the processor creation needs to have at least one existing path.
// That's why the tests below check for the config validation and the processor creation.
static const std::string CONFIG =
"ocio_profile_version: 2\n"
@@ -1463,19 +1551,88 @@ OCIO_ADD_TEST(Config, context_variable_with_search_path)
std::istringstream iss;
iss.str(CONFIG);
// $ENV1 exists in the config itself.
OCIO::ConfigRcPtr cfg;
OCIO_CHECK_NO_THROW(cfg = OCIO::Config::CreateFromStream(iss)->createEditableCopy());
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
/// Remove the context variable.
/// Remove the context variable so, there is no more successful path.
OCIO_CHECK_NO_THROW(cfg->addEnvironmentVar("ENV1", nullptr));
OCIO_CHECK_THROW_WHAT(cfg->validate(), OCIO::Exception,
"The search_path '$ENV1' cannot be resolved.");
#ifdef _WIN32
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. ");
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: '$ENV1\\lut1d_green.ctf'.");
#else
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: '$ENV1/lut1d_green.ctf'.");
#endif
// The following tests validate that in a list of search paths at least one can be resolved.
{
// Change the search_path to have at least one successful path i.e. the first one.
const std::string searchPath = OCIO::GetTestFilesDir() + ":$ENV1";
OCIO_CHECK_NO_THROW(cfg->setSearchPath(searchPath.c_str()));
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
}
{
// Change the search_path to have at least one successful path i.e. the second one.
const std::string searchPath = "$ENV1:" + OCIO::GetTestFilesDir();
OCIO_CHECK_NO_THROW(cfg->setSearchPath(searchPath.c_str()));
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
}
{
// Change the search_path to have at least one successful path i.e. the first one.
const std::string searchPath = OCIO::GetTestFilesDir() + ":";
OCIO_CHECK_NO_THROW(cfg->setSearchPath(searchPath.c_str()));
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
}
{
// Change the search_path to have at least one successful path i.e. the second one.
const std::string searchPath = ":" + OCIO::GetTestFilesDir();
OCIO_CHECK_NO_THROW(cfg->setSearchPath(searchPath.c_str()));
OCIO_CHECK_NO_THROW(cfg->validate());
OCIO_CHECK_NO_THROW(cfg->getProcessor("cs1", "cs2"));
}
// The following test highlights the difference between the validation and the processor
// creation related to the search paths i.e. resolved vs. existing search paths.
{
// Change the search_path to have at least one potentially successful path
// i.e. the second one.
const std::string searchPath = "$ENV1:faulty/path";
OCIO_CHECK_NO_THROW(cfg->setSearchPath(searchPath.c_str()));
// The validation succeeds because the first path does not resolve but the second path does.
OCIO_CHECK_NO_THROW(cfg->validate());
// The first path does not resolve and the second path does resolve but it does not exist
// so the processor creation fails.
#ifdef _WIN32
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: "
"'$ENV1\\lut1d_green.ctf' : 'faulty\\path\\lut1d_green.ctf'.");
#else
OCIO_CHECK_THROW_WHAT(cfg->getProcessor("cs1", "cs2"), OCIO::Exception,
"The specified file reference 'lut1d_green.ctf' could not be located. "
"The following attempts were made: "
"'$ENV1/lut1d_green.ctf' : 'faulty/path/lut1d_green.ctf'.");
#endif
}
}
OCIO_ADD_TEST(Config, role_without_colorspace)
File diff suppressed because it is too large Load Diff
+95 -28
View File
@@ -17,17 +17,35 @@ OCIO_ADD_TEST(Platform, envVariable)
// Only validates the public API.
// Complete validations are done below using the private methods.
const char * path = OCIO::GetEnvVariable("PATH");
const char * path = OCIO::GetEnvVariable(u8"PATH");
OCIO_CHECK_ASSERT(path && *path);
OCIO::SetEnvVariable("MY_DUMMY_ENV", "SomeValue");
const char * value = OCIO::GetEnvVariable("MY_DUMMY_ENV");
OCIO::SetEnvVariable(u8"MY_DUMMY_ENV", u8"SomeValue");
const char * value = OCIO::GetEnvVariable(u8"MY_DUMMY_ENV");
OCIO_CHECK_ASSERT(value && *value);
OCIO_CHECK_EQUAL(std::string(value), "SomeValue");
OCIO_CHECK_EQUAL(std::string(value), u8"SomeValue");
OCIO::UnsetEnvVariable("MY_DUMMY_ENV");
value = OCIO::GetEnvVariable("MY_DUMMY_ENV");
#ifdef _WIN32
// Assert that we retrieve the correct value from the Windows API too.
uint32_t win_env_sz = GetEnvironmentVariable(TEXT("MY_DUMMY_ENV"), NULL, 0);
OCIO_CHECK_NE(win_env_sz, 0);
std::tstring win_env_value(win_env_sz, 0);
GetEnvironmentVariable(TEXT("MY_DUMMY_ENV"), &win_env_value[0], win_env_sz);
win_env_value.pop_back(); // Remove null terminator that interferes with comparison
OCIO_CHECK_ASSERT(win_env_value == TEXT("SomeValue"));
#endif
OCIO::UnsetEnvVariable(u8"MY_DUMMY_ENV");
value = OCIO::GetEnvVariable(u8"MY_DUMMY_ENV");
OCIO_CHECK_ASSERT(!value || !*value);
#ifdef _WIN32
// Assert that the variable has been unset from the Windows API too, which will result in
// GetEnvironmentVariable returning 0 and GetLastError returning ERROR_ENVVAR_NOT_FOUND.
OCIO_CHECK_EQUAL(GetEnvironmentVariable(TEXT("MY_DUMMY_ENV"), NULL, 0), 0);
OCIO_CHECK_EQUAL(GetLastError(), ERROR_ENVVAR_NOT_FOUND);
#endif
}
OCIO_ADD_TEST(Platform, getenv)
@@ -52,6 +70,32 @@ OCIO_ADD_TEST(Platform, getenv)
OCIO_CHECK_ASSERT(OCIO::Platform::Getenv("PATH", env));
OCIO_CHECK_ASSERT(!env.empty());
#ifdef _WIN32
// Assert that all results match in Windows API.
// Assert this variable doesn't exist, which will result in GetEnvironmentVariable returning
// 0 and GetLastError returning ERROR_ENVVAR_NOT_FOUND.
OCIO_CHECK_EQUAL(GetEnvironmentVariable(TEXT("NotExistingEnvVariable"), NULL, 0), 0);
OCIO_CHECK_EQUAL(GetLastError(), ERROR_ENVVAR_NOT_FOUND);
// Assert this variable does exist.
OCIO_CHECK_NE(GetEnvironmentVariable(TEXT("PATH"), NULL, 0), 0);
// Create a variable and test that it's retrievable through the Windows API.
OCIO::Platform::Setenv(u8"MY_WINDOWS_DUMMY_ENV", u8"SomeValue");
uint32_t win_env_sz = GetEnvironmentVariable(TEXT("MY_WINDOWS_DUMMY_ENV"), NULL, 0);
OCIO_CHECK_NE(win_env_sz, 0);
std::tstring win_env_value(win_env_sz, 0);
GetEnvironmentVariable(TEXT("MY_WINDOWS_DUMMY_ENV"), &win_env_value[0], win_env_sz);
win_env_value.pop_back(); // Remove null terminator that interferes with comparison
OCIO_CHECK_ASSERT(win_env_value == TEXT("SomeValue"));
OCIO::Platform::Unsetenv(u8"MY_WINDOWS_DUMMY_ENV");
OCIO_CHECK_EQUAL(GetEnvironmentVariable(TEXT("MY_WINDOWS_DUMMY_ENV"), NULL, 0), 0);
OCIO_CHECK_EQUAL(GetLastError(), ERROR_ENVVAR_NOT_FOUND);
#endif
}
OCIO_ADD_TEST(Platform, setenv)
@@ -62,61 +106,61 @@ OCIO_ADD_TEST(Platform, setenv)
Guard() = default;
~Guard()
{
OCIO::Platform::Unsetenv("MY_DUMMY_ENV");
OCIO::Platform::Unsetenv("MY_WINDOWS_DUMMY_ENV");
OCIO::Platform::Unsetenv(u8"MY_DUMMY_ENV");
OCIO::Platform::Unsetenv(u8"MY_WINDOWS_DUMMY_ENV");
}
} guard;
{
OCIO::Platform::Setenv("MY_DUMMY_ENV", "SomeValue");
OCIO::Platform::Setenv(u8"MY_DUMMY_ENV", u8"SomeValue");
std::string env;
OCIO_CHECK_ASSERT(OCIO::Platform::Getenv("MY_DUMMY_ENV", env));
OCIO_CHECK_ASSERT(OCIO::Platform::Getenv(u8"MY_DUMMY_ENV", env));
OCIO_CHECK_ASSERT(!env.empty());
OCIO_CHECK_ASSERT(0==std::strcmp("SomeValue", env.c_str()));
OCIO_CHECK_EQUAL(strlen("SomeValue"), env.size());
OCIO_CHECK_ASSERT(0==std::strcmp(u8"SomeValue", env.c_str()));
OCIO_CHECK_EQUAL(strlen(u8"SomeValue"), env.size());
}
{
OCIO::Platform::Setenv("MY_DUMMY_ENV", " ");
OCIO::Platform::Setenv(u8"MY_DUMMY_ENV", u8" ");
std::string env;
OCIO_CHECK_ASSERT(OCIO::Platform::Getenv("MY_DUMMY_ENV", env));
OCIO_CHECK_ASSERT(OCIO::Platform::Getenv(u8"MY_DUMMY_ENV", env));
OCIO_CHECK_ASSERT(!env.empty());
OCIO_CHECK_ASSERT(0==std::strcmp(" ", env.c_str()));
OCIO_CHECK_EQUAL(std::strlen(" "), env.size());
OCIO_CHECK_ASSERT(0==std::strcmp(u8" ", env.c_str()));
OCIO_CHECK_EQUAL(std::strlen(u8" "), env.size());
}
{
OCIO::Platform::Unsetenv("MY_DUMMY_ENV");
OCIO::Platform::Unsetenv(u8"MY_DUMMY_ENV");
std::string env;
OCIO_CHECK_ASSERT(!OCIO::Platform::Getenv("MY_DUMMY_ENV", env));
OCIO_CHECK_ASSERT(!OCIO::Platform::Getenv(u8"MY_DUMMY_ENV", env));
OCIO_CHECK_ASSERT(env.empty());
}
#ifdef _WIN32
{
SetEnvironmentVariable("MY_WINDOWS_DUMMY_ENV", "1");
SetEnvironmentVariable(TEXT("MY_WINDOWS_DUMMY_ENV"), TEXT("1"));
std::string env;
OCIO_CHECK_ASSERT(OCIO::Platform::Getenv("MY_WINDOWS_DUMMY_ENV", env));
OCIO_CHECK_EQUAL(env, std::string("1"));
OCIO_CHECK_ASSERT(OCIO::Platform::Getenv(u8"MY_WINDOWS_DUMMY_ENV", env));
OCIO_CHECK_EQUAL(env, std::string(u8"1"));
}
{
SetEnvironmentVariable("MY_WINDOWS_DUMMY_ENV", " ");
SetEnvironmentVariable(TEXT("MY_WINDOWS_DUMMY_ENV"), TEXT(" "));
std::string env;
OCIO_CHECK_ASSERT(OCIO::Platform::Getenv("MY_WINDOWS_DUMMY_ENV", env));
OCIO_CHECK_EQUAL(env, std::string(" "));
OCIO_CHECK_ASSERT(OCIO::Platform::Getenv(u8"MY_WINDOWS_DUMMY_ENV", env));
OCIO_CHECK_EQUAL(env, std::string(u8" "));
}
{
// Windows SetEnvironmentVariable() sets the env. variable to empty like
// the Linux ::setenv() in contradiction with the Windows _putenv_s().
SetEnvironmentVariable("MY_WINDOWS_DUMMY_ENV", "");
SetEnvironmentVariable(TEXT("MY_WINDOWS_DUMMY_ENV"), TEXT(""));
std::string env;
OCIO_CHECK_ASSERT(OCIO::Platform::Getenv("MY_WINDOWS_DUMMY_ENV", env));
OCIO_CHECK_ASSERT(OCIO::Platform::Getenv(u8"MY_WINDOWS_DUMMY_ENV", env));
OCIO_CHECK_ASSERT(env.empty());
}
{
SetEnvironmentVariable("MY_WINDOWS_DUMMY_ENV", nullptr);
SetEnvironmentVariable(TEXT("MY_WINDOWS_DUMMY_ENV"), nullptr);
std::string env;
OCIO_CHECK_ASSERT(!OCIO::Platform::Getenv("MY_WINDOWS_DUMMY_ENV", env));
OCIO_CHECK_ASSERT(!OCIO::Platform::Getenv(u8"MY_WINDOWS_DUMMY_ENV", env));
OCIO_CHECK_ASSERT(env.empty());
}
#endif
@@ -160,3 +204,26 @@ OCIO_ADD_TEST(Platform, create_temp_filename)
// Check that it only generates unique random strings.
OCIO_CHECK_EQUAL(uids.size(), TestMax);
}
OCIO_ADD_TEST(Platform, utf8_utf16_convert)
{
#ifdef _WIN32
// Define the same string in both UTF-8 and UTF-16LE encoding:
// - Hiragana letter KO: xe3, x81, x93 x3053
// - Hiragana letter N: xe3, x82, x93 x3093
// - Hiragana letter NI: xe3, x81, xab x306b
// - Hiragana letter CHI: xe3, x81, xa1 x3061
// - Hiragana letter HA/WA: xe3, x81, xaf x306f
std::string utf8_str = "\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf";
std::wstring utf16_str = L"\x3053\x3093\x306b\x3061\x306f";
// Convert each string to the other encoding and assert that the result matches the other
std::string utf16_to_utf8 = OCIO::Platform::Utf16ToUtf8(utf16_str);
std::wstring utf8_to_utf16 = OCIO::Platform::Utf8ToUtf16(utf8_str);
OCIO_CHECK_EQUAL(utf16_to_utf8, utf8_str);
// wstring can't be sent to cout, so we run an assert
OCIO_CHECK_ASSERT(wcscmp(utf8_to_utf16.c_str(), utf16_str.c_str()) == 0);
#endif
}
+2 -1
View File
@@ -11,6 +11,7 @@
#include "MathUtils.h"
#include "Op.h"
#include "Platform.h"
#include "pystring/pystring.h"
namespace OCIO_NAMESPACE
@@ -43,7 +44,7 @@ OCIO_SHARED_PTR<LocalCachedFile> LoadTestFile(
// Open the filePath
std::ifstream filestream;
filestream.open(filePath.c_str(), mode);
Platform::OpenInputFileStream(filestream, filePath.c_str(), mode);
if (!filestream.is_open())
{
+24 -6
View File
@@ -5725,9 +5725,9 @@ OCIO_ADD_TEST(CTFTransform, cdl_clf)
<SOPNode>
<Description>SOP description 1</Description>
<Description>SOP description 2</Description>
<Slope>1, 1.1, 1.2</Slope>
<Offset>0.2, 0.3, 0.4</Offset>
<Power>3.1, 3.2, 3.3</Power>
<Slope>1 1.1 1.2</Slope>
<Offset>0.2 0.3 0.4</Offset>
<Power>3.1 3.2 3.3</Power>
</SOPNode>
<SatNode>
<Description>Sat description 1</Description>
@@ -5740,6 +5740,24 @@ OCIO_ADD_TEST(CTFTransform, cdl_clf)
OCIO_CHECK_EQUAL(expected.size(), outputTransform.str().size());
OCIO_CHECK_EQUAL(expected, outputTransform.str());
// Now test if the read is working.
std::istringstream ctfStream;
ctfStream.str(expected);
std::string emptyString;
OCIO::LocalFileFormat tester;
OCIO::CachedFileRcPtr file = tester.read(ctfStream, emptyString, OCIO::INTERP_DEFAULT);
auto cachedFile = OCIO::DynamicPtrCast<OCIO::LocalCachedFile>(file);
const OCIO::ConstOpDataVec & opList = cachedFile->m_transform->getOps();
OCIO_REQUIRE_EQUAL(opList.size(), 1);
auto cdlData = std::dynamic_pointer_cast<const OCIO::CDLOpData>(opList[0]);
OCIO_REQUIRE_ASSERT(cdlData);
OCIO_CHECK_EQUAL(cdlData->getSlopeParams()[0], 1.);
OCIO_CHECK_EQUAL(cdlData->getSlopeParams()[1], 1.1);
OCIO_CHECK_EQUAL(cdlData->getSlopeParams()[2], 1.2);
}
OCIO_ADD_TEST(CTFTransform, cdl_ctf)
@@ -5768,9 +5786,9 @@ OCIO_ADD_TEST(CTFTransform, cdl_ctf)
"<ProcessList version=\"1.7\" id=\"cdl2\">\n"
" <ASC_CDL inBitDepth=\"32f\" outBitDepth=\"32f\" style=\"Fwd\">\n"
" <SOPNode>\n"
" <Slope>1, 1.1, 1.2</Slope>\n"
" <Offset>0.2, 0.3, 0.4</Offset>\n"
" <Power>3.1, 3.2, 3.3</Power>\n"
" <Slope>1 1.1 1.2</Slope>\n"
" <Offset>0.2 0.3 0.4</Offset>\n"
" <Power>3.1 3.2 3.3</Power>\n"
" </SOPNode>\n"
" <SatNode>\n"
" <Saturation>2.1</Saturation>\n"
@@ -176,14 +176,14 @@ OCIO_ADD_TEST(GradingRGBCurveOpCPU, log)
OCIO_CHECK_NO_THROW(op = OCIO::GetGradingRGBCurveCPURenderer(gcc));
OCIO_CHECK_ASSERT(op);
const long num_samples = 2;
constexpr long num_samples = 2;
float res[4 * num_samples]{ 0.f };
const float input_32f[] = {
constexpr float input_32f[] = {
-0.2f, 0.2f, 0.5f, 0.0f,
0.8f, 1.0f, 2.0f, 0.5f };
const float expected_32f[] = {
constexpr float expected_32f[] = {
0.25306581f, 0.35779659f, 0.98416632f, 0.0f,
1.09451043f, 1.54596428f, 1.78067802f, 0.5f };
@@ -219,14 +219,14 @@ OCIO_ADD_TEST(GradingRGBCurveOpCPU, log_partial_identity)
OCIO_CHECK_NO_THROW(op = OCIO::GetGradingRGBCurveCPURenderer(gcc));
OCIO_CHECK_ASSERT(op);
const long num_samples = 2;
constexpr long num_samples = 2;
float res[4 * num_samples]{ 0.f };
float input_32f[] = {
-0.2f, 0.2f, 0.5f, 0.0f,
0.8f, 1.0f, 2.0f, 0.5f };
const float expected_32f[] = {
constexpr float expected_32f[] = {
-0.2f, 0.15779659f, 0.5f, 0.0f,
0.8f, 1.34596419f, 2.0f, 0.5f };
@@ -264,14 +264,14 @@ OCIO_ADD_TEST(GradingRGBCurveOpCPU, monotonic)
OCIO_CHECK_NO_THROW(op = OCIO::GetGradingRGBCurveCPURenderer(gcc));
OCIO_CHECK_ASSERT(op);
const long num_samples = 2;
constexpr long num_samples = 2;
float res[4 * num_samples]{ 0.f };
float input_32f[] = {
0.8f, 0.2f, 0.5f, 0.0f,
0.9f, 1.0f, 2.0f, 0.5f };
const float expected_32f[] = {
constexpr float expected_32f[] = {
0.52230538f, 0.2f, 0.5f, 0.0f,
0.68079938f, 1.0f, 2.0f, 0.5f };
@@ -311,14 +311,14 @@ OCIO_ADD_TEST(GradingRGBCurveOpCPU, lin_bypass)
OCIO_CHECK_NO_THROW(op = OCIO::GetGradingRGBCurveCPURenderer(gcc));
OCIO_CHECK_ASSERT(op);
const long num_samples = 2;
constexpr long num_samples = 2;
float res[4 * num_samples]{ 0.f };
float input_32f[] = {
-8.f, -3.f, -1.f, 0.0f,
1.f, 2.5f, 4.0f, 0.5f };
const float expected_32f[] = {
constexpr float expected_32f[] = {
-8.50508935f, -6.37181915f, -3.01264257f, 0.0f,
1.95205522f, 4.76796850f, 5.76796850f, 0.5f };
@@ -357,14 +357,14 @@ OCIO_ADD_TEST(GradingRGBCurveOpCPU, lin)
OCIO_CHECK_NO_THROW(op = OCIO::GetGradingRGBCurveCPURenderer(gcc));
OCIO_CHECK_ASSERT(op);
const long num_samples = 2;
constexpr long num_samples = 2;
float res[4 * num_samples]{ 0.f };
float input_32f[] = {
-0.003f, 0.02f, 0.09f, 0.0f,
0.360f, 1.00f, 3.00f, 0.5f };
const float expected_32f[] = {
constexpr float expected_32f[] = {
-4.20784139e-03f, 1.26825221e-03f, 2.23983977e-02f, 0.0f,
6.96706128e-01f, 4.79411018e+00f, 9.95152432e+00f, 0.5f };
@@ -410,14 +410,33 @@ OCIO_ADD_TEST(GradingRGBCurveOpCPU, slopes)
OCIO_CHECK_NO_THROW(op = OCIO::GetGradingRGBCurveCPURenderer(gcc));
OCIO_CHECK_ASSERT(op);
const long num_samples = 1;
constexpr long num_samples = 2;
float input_32f[] = {
-3.f, -1.f, 1.f, 0.5f };
-3.f, -1.f, 1.f, 0.5f,
-7.f, 0.f, 7.f, 1.0f };
// Test that the slopes were used (the values are significantly different without slopes).
const float expected_32f[] = {
-2.92582282f, 0.28069129f, 2.81987724f, 0.5f };
constexpr float expected_32f[] = {
-2.92582282f, 0.28069129f, 2.81987724f, 0.5f,
-4.0f, 1.73250193f, 4.0f, 1.0f };
OCIO_CHECK_NO_THROW(op->apply(input_32f, input_32f, num_samples));
ValidateImage(expected_32f, input_32f, num_samples, __LINE__);
// Test in inverse direction.
float rev_input_32f[] = {
-2.92582282f, 0.28069129f, 2.81987724f, 0.5f,
-7.0f, 1.73250193f, 7.0f, 1.0f };
constexpr float rev_expected_32f[] = {
-3.f, -1.f, 1.f, 0.5f,
-5.26017743f, 0.f, 4.67381243f, 1.0f };
gc->setDirection(OCIO::TRANSFORM_DIR_INVERSE);
OCIO_CHECK_NO_THROW(op = OCIO::GetGradingRGBCurveCPURenderer(gcc));
OCIO_CHECK_ASSERT(op);
OCIO_CHECK_NO_THROW(op->apply(rev_input_32f, rev_input_32f, num_samples));
ValidateImage(rev_expected_32f, rev_input_32f, num_samples, __LINE__);
}
@@ -412,3 +412,32 @@ OCIO_ADD_TEST(GradingPrimaryTransform, log_contrast_inverse_apply)
OCIO_CHECK_CLOSE(pixel[1], pixelRef[1], error);
OCIO_CHECK_CLOSE(pixel[2], pixelRef[2], error);
}
OCIO_ADD_TEST(GradingPrimaryTransform, local_bypass)
{
// Test that the GPU is empty for an identity transform.
OCIO::GradingPrimaryTransformRcPtr transform
= OCIO::GradingPrimaryTransform::Create(OCIO::GRADING_LOG);
OCIO::ConstConfigRcPtr config = OCIO::Config::CreateRaw();
OCIO::ConstProcessorRcPtr proc = config->getProcessor(transform);
OCIO::ConstGPUProcessorRcPtr gpu = proc->getOptimizedGPUProcessor(OCIO::OPTIMIZATION_NONE);
OCIO::GpuShaderDescRcPtr shaderDesc = OCIO::GpuShaderDesc::CreateShaderDesc();
OCIO_CHECK_NO_THROW(gpu->extractGpuShaderInfo(shaderDesc));
static const std::string gpuStr("\n"
"// Declaration of the OCIO shader function\n"
"\n"
"vec4 OCIOMain(vec4 inPixel)\n"
"{\n"
" vec4 outColor = inPixel;\n"
"\n"
" return outColor;\n"
"}\n");
OCIO_CHECK_EQUAL(gpuStr, std::string(shaderDesc->getShaderText()));
}
@@ -271,3 +271,32 @@ OCIO_ADD_TEST(GradingRGBCurveTransform, serialization)
}
}
OCIO_ADD_TEST(GradingRGBCurveTransform, local_bypass)
{
// Test that the GPU is empty for an identity transform.
OCIO::GradingRGBCurveTransformRcPtr transform
= OCIO::GradingRGBCurveTransform::Create(OCIO::GRADING_LOG);
OCIO::ConstConfigRcPtr config = OCIO::Config::CreateRaw();
OCIO::ConstProcessorRcPtr proc = config->getProcessor(transform);
OCIO::ConstGPUProcessorRcPtr gpu = proc->getOptimizedGPUProcessor(OCIO::OPTIMIZATION_NONE);
OCIO::GpuShaderDescRcPtr shaderDesc = OCIO::GpuShaderDesc::CreateShaderDesc();
OCIO_CHECK_NO_THROW(gpu->extractGpuShaderInfo(shaderDesc));
static const std::string gpuStr("\n"
"// Declaration of the OCIO shader function\n"
"\n"
"vec4 OCIOMain(vec4 inPixel)\n"
"{\n"
" vec4 outColor = inPixel;\n"
"\n"
" return outColor;\n"
"}\n");
OCIO_CHECK_EQUAL(gpuStr, std::string(shaderDesc->getShaderText()));
}

Some files were not shown because too many files have changed in this diff Show More