Compare commits
27
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e414bc9c0 | ||
|
|
3227fa3f76 | ||
|
|
ffba80b34c | ||
|
|
0c2aacb6c9 | ||
|
|
6c8cf83375 | ||
|
|
7a76cceb57 | ||
|
|
b37089aefb | ||
|
|
177a927ff5 | ||
|
|
a64e4d5d48 | ||
|
|
198c888ee9 | ||
|
|
b252372b7c | ||
|
|
17e52e38c6 | ||
|
|
7360206858 | ||
|
|
934b80829b | ||
|
|
36845c3f32 | ||
|
|
2d318af010 | ||
|
|
445c45b016 | ||
|
|
d950ab4bf7 | ||
|
|
d331992d93 | ||
|
|
9c5a324184 | ||
|
|
2716337500 | ||
|
|
30ac2904e3 | ||
|
|
ce3042cd10 | ||
|
|
15ffc9a414 | ||
|
|
7ec43b7d93 | ||
|
|
83d3412ff2 | ||
|
|
156d4ffda0 |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Copyright Contributors to the OpenColorIO Project.
|
||||
|
||||
add_subdirectory(OpenColorIO)
|
||||
@@ -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
|
||||
)
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 ()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
@@ -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
|
||||
)
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: '"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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") << ";";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -40,5 +40,5 @@ target_link_libraries(ociobakelut
|
||||
)
|
||||
|
||||
install(TARGETS ociobakelut
|
||||
RUNTIME DESTINATION bin
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
@@ -28,5 +28,5 @@ target_link_libraries(ociocheck
|
||||
)
|
||||
|
||||
install(TARGETS ociocheck
|
||||
RUNTIME DESTINATION bin
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
@@ -36,5 +36,5 @@ target_link_libraries(ociochecklut
|
||||
)
|
||||
|
||||
install(TARGETS ociochecklut
|
||||
RUNTIME DESTINATION bin
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
@@ -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}
|
||||
)
|
||||
|
||||
@@ -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()))
|
||||
|
||||
@@ -45,5 +45,5 @@ target_link_libraries(ociodisplay
|
||||
OpenImageIO::OpenImageIO
|
||||
)
|
||||
install(TARGETS ociodisplay
|
||||
RUNTIME DESTINATION bin
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -26,5 +26,5 @@ target_link_libraries(ociolutimage
|
||||
)
|
||||
|
||||
install(TARGETS ociolutimage
|
||||
RUNTIME DESTINATION bin
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
@@ -29,5 +29,5 @@ target_link_libraries(ociomakeclf
|
||||
)
|
||||
|
||||
install(TARGETS ociomakeclf
|
||||
RUNTIME DESTINATION bin
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
@@ -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}
|
||||
)
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ namespace OIIO = OIIO_NAMESPACE;
|
||||
|
||||
#include "apputils/argparse.h"
|
||||
#include "oiiohelpers.h"
|
||||
#include "utils/Half.h"
|
||||
#include "utils/StringUtils.h"
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +24,5 @@ target_link_libraries(ociowrite
|
||||
)
|
||||
|
||||
install(TARGETS ociowrite
|
||||
RUNTIME DESTINATION bin
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
|
||||
@@ -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
@@ -0,0 +1,3 @@
|
||||
numpy
|
||||
PyOpenGL
|
||||
PySide2
|
||||
@@ -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/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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>(
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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());
|
||||
})
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
|
||||
#include "oiiohelpers.h"
|
||||
#include "utils/Half.h"
|
||||
#include "utils/StringUtils.h"
|
||||
|
||||
|
||||
|
||||
@@ -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}/.."
|
||||
)
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user