Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions .github/workflows/ci_workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ jobs:
build-openfx: 'ON'
use-simd: 'ON'
use-oiio: 'ON'
aswf-ocio-version: 2.5.2
cxx-standard: 20
cxx-compiler: clang++
cc-compiler: clang
Expand Down Expand Up @@ -115,6 +116,7 @@ jobs:
build-openfx: 'ON'
use-simd: 'ON'
use-oiio: 'ON'
aswf-ocio-version: 2.4.2
cxx-standard: 20
cxx-compiler: clang++
cc-compiler: clang
Expand Down Expand Up @@ -157,6 +159,7 @@ jobs:
build-openfx: 'ON'
use-simd: 'ON'
use-oiio: 'ON'
aswf-ocio-version: 2.3.2
cxx-standard: 20
cxx-compiler: clang++
cc-compiler: clang
Expand Down Expand Up @@ -199,12 +202,12 @@ jobs:
build-openfx: 'ON'
use-simd: 'ON'
use-oiio: 'ON'
aswf-ocio-version: 2.2.1
cxx-standard: 20
cxx-compiler: clang++
cc-compiler: clang
compiler-desc: Clang
vfx-cy: 2023
container-tag: 2023.2
install-ext-packages: MISSING
- build: 2
build-type: Release
Expand All @@ -218,7 +221,6 @@ jobs:
cc-compiler: gcc
compiler-desc: GCC
vfx-cy: 2023
container-tag: 2023.2
install-ext-packages: ALL
- build: 1
build-type: Release
Expand All @@ -232,7 +234,6 @@ jobs:
cc-compiler: gcc
compiler-desc: GCC
vfx-cy: 2023
container-tag: 2023.2
install-ext-packages: ALL
env:
CXX: ${{ matrix.cxx-compiler }}
Expand All @@ -245,6 +246,13 @@ jobs:
if: matrix.build-docs == 'ON'
- name: Install tests env
run: share/ci/scripts/linux/dnf/install_tests_env.sh
- name: Install ASWF OpenColorIO for OpenImageIO
# The container's prebuilt OpenImageIO is linked against a specific
# OpenColorIO release that the container does not ship (it's built
# from source here instead). Fetch that release from the ASWF Conan
# remote so OpenImageIO's dependency resolves at link/run time.
if: matrix.use-oiio == 'ON'
run: share/ci/scripts/linux/dnf/install_aswf_opencolorio.sh ${{ matrix.aswf-ocio-version }} ${{ matrix.vfx-cy }}
- name: Create build directories
run: |
mkdir _install
Expand Down Expand Up @@ -316,7 +324,7 @@ jobs:
working-directory: _build/tests/cmake-consumer-dist

# ---------------------------------------------------------------------------
# macOS
# macOS Intel
# ---------------------------------------------------------------------------

macos:
Expand Down Expand Up @@ -497,12 +505,19 @@ jobs:
if: matrix.build-docs == 'ON'
- name: Install tests env
run: share/ci/scripts/macos/install_tests_env.sh
- name: Install OIIO
if: matrix.use-oiio == 'ON'
run: time share/ci/scripts/macos/install_oiio.sh
- name: Create build directories
run: |
mkdir _install
mkdir _build
- name: Configure
run: |
OIIO_CMAKE_ARGS=()
if [ "${{ matrix.use-oiio }}" = "ON" ]; then
OIIO_CMAKE_ARGS+=(-DOpenImageIO_ROOT=$(brew --prefix openimageio))
fi
cmake ../. \
-DCMAKE_INSTALL_PREFIX=../_install \
-DCMAKE_BUILD_TYPE=${{ matrix.build-type }} \
Expand All @@ -516,7 +531,8 @@ jobs:
-DOCIO_INSTALL_EXT_PACKAGES=ALL \
-DOCIO_WARNING_AS_ERROR=ON \
-DPython_EXECUTABLE=$(which python) \
-DCMAKE_OSX_ARCHITECTURES="${{ matrix.arch-type }}"
-DCMAKE_OSX_ARCHITECTURES="${{ matrix.arch-type }}" \
"${OIIO_CMAKE_ARGS[@]}"
working-directory: _build
- name: Build
run: |
Expand Down Expand Up @@ -602,7 +618,8 @@ jobs:
build-docs: 'OFF'
build-openfx: 'ON'
use-simd: 'OFF'
use-oiio: 'ON'
# NB: OIIO is not currently set up for Windows CI builds
use-oiio: 'OFF'
cxx-standard: 20
python-version: '3.13'
- build: 3
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/dependencies_latest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ jobs:
run: |
vcpkg install zlib:x64-windows
vcpkg install tiff:x64-windows
vcpkg install directx-headers:x64-windows
shell: bash
- name: Install fixed ext package versions
# Minizip-ng depends on ZLIB. ZLIB must be installed first.
Expand Down
4 changes: 2 additions & 2 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
version: 2

build:
os: ubuntu-20.04
os: ubuntu-lts-latest
tools:
python: "3.11"
python: "3.14"

sphinx:
configuration: docs/conf.py
Expand Down
33 changes: 33 additions & 0 deletions share/ci/scripts/linux/dnf/install_aswf_opencolorio.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: BSD-3-Clause
# Copyright Contributors to the OpenColorIO Project.
#
# The aswf/ci-ocio container images intentionally do not ship OpenColorIO,
# since the whole point of the image is to build OpenColorIO from source.
# However, the container's prebuilt OpenImageIO is dynamically linked
# against the specific OpenColorIO release used by the corresponding
# aswf-docker VFX Reference Platform year, and that library is not present
# in the image. Fetch the matching prebuilt OpenColorIO shared library from
# the ASWF Conan remote and stage it on the linker search path, so apps
# built against OCIO_USE_OIIO_FOR_APPS=ON can resolve OpenImageIO's
# transitive dependency at link and run time.
#
# Usage: install_aswf_opencolorio.sh <opencolorio-version> <vfx-year>

set -ex

OCIO_VERSION="$1"
VFX_YEAR="$2"
CONAN_REF="opencolorio/${OCIO_VERSION}@aswf/vfx${VFX_YEAR}"

conan remote add aswf https://linuxfoundation.jfrog.io/artifactory/api/conan/aswf-conan

PKG_ID=$(conan list "${CONAN_REF}:*" -r aswf --format=json 2>/dev/null \
| jq -r --arg ref "${CONAN_REF}" '.aswf[$ref].revisions | to_entries[0].value.packages | keys[0]')

conan download "${CONAN_REF}:${PKG_ID}" -r aswf

PKG_PATH=$(conan cache path "${CONAN_REF}:${PKG_ID}")

cp -P "${PKG_PATH}"/lib/libOpenColorIO.so* /usr/local/lib/
ldconfig
13 changes: 6 additions & 7 deletions share/ci/scripts/macos/install_oiio.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@

set -ex

OIIO_VERSION="$1"

if [ "$OIIO_VERSION" = "latest" ]; then
brew install openimageio
else
brew install openimageio@${OIIO_VERSION}
fi
# Homebrew does not publish versioned openimageio@X formulae (unlike e.g. python@X), so a
# specific version cannot be pinned here without installing from an old homebrew-core formula
# commit, which risks building OIIO and its whole dependency tree from source if no bottle
# exists for that commit on the runner's current macOS/Xcode. Always install whatever the
# current bottle is instead.
brew install openimageio
4 changes: 4 additions & 0 deletions share/cmake/modules/FindDirectX-Headers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ if(NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL ALL)
if(directx-headers_VERSION)
set(DirectX-Headers_VERSION ${directx-headers_VERSION})
endif()
if(TARGET Microsoft::DirectX-Headers AND NOT DirectX-Headers_INCLUDE_DIR)
get_target_property(DirectX-Headers_INCLUDE_DIR
Microsoft::DirectX-Headers INTERFACE_INCLUDE_DIRECTORIES)
endif()
else()
# Fall back to locating the public header directly (e.g. when the
# headers were installed without the CMake config, or are provided
Expand Down
7 changes: 6 additions & 1 deletion share/cmake/modules/FindExtPackages.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,12 @@ endif()

if(OCIO_BUILD_APPS)

if(OCIO_USE_OIIO_FOR_APPS AND OpenImageIO_FOUND AND TARGET OpenImageIO::OpenImageIO)
if(OCIO_USE_OIIO_FOR_APPS)
if(NOT (OpenImageIO_FOUND AND TARGET OpenImageIO::OpenImageIO))
message(FATAL_ERROR "OCIO_USE_OIIO_FOR_APPS is ON but OpenImageIO was not found. "
"Either install OpenImageIO or turn OCIO_USE_OIIO_FOR_APPS off "
"to build ociolutimage, ocioconvert and ociodisplay against OpenEXR instead.")
endif()
if (USE_MSVC AND OCIO_IMAGE_BACKEND STREQUAL "OpenImageIO")
# Temporary until fixed in OpenImageIO: Mute some warnings from OpenImageIO farmhash.h
# C4267 (level 3) 'var' : conversion from 'size_t' to 'type', possible loss of data
Expand Down
12 changes: 12 additions & 0 deletions src/OpenColorIO/CPUInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,18 @@ CPUInfo::CPUInfo()
{
cpuid(0x80000002 + index, (int *)(name + 16*index));
}

// AMD erratum #1485 (Zen4, e.g. EPYC 8004/9004 and Ryzen 7000 series): when SMT is
// enabled and STIBP is not, affected CPUs can corrupt their own instruction stream
// during speculative execution, raising a spurious illegal-instruction fault on
// otherwise-correct code. There is no cheap, portable, unprivileged way to check the
// actual STIBP enablement state from here, and the documented Zen4 model numbers are
// scattered/non-contiguous, so this only blocks the exact SKU seen to hit this in
// practice rather than guessing at a broader family/model range.
if (!strncmp(vendor, "AuthenticAMD", 12) && strstr(name, "EPYC 9V45"))
{
flags &= ~X86_CPU_FLAG_AVX512;
}
}

#elif defined(__aarch64__) || defined(_M_ARM64) // ARM 64-bit processor (multiple platforms)
Expand Down
5 changes: 5 additions & 0 deletions tests/cpu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ function(add_ocio_test NAME SOURCES TESTS PRIVATE_INCLUDES)

if(OCIO_USE_AVX512)
add_ocio_test_variant(${TEST_NAME}_avx512 ${TEST_BINARY} --avx512)
# Runs in its own process, independent of the full suite above, so it still
# executes (and reports its own result) even if some other AVX512 test crashes
# the ${TEST_NAME}_avx512 process before reaching it.
add_ocio_test_variant(${TEST_NAME}_avx512_diag ${TEST_BINARY} --avx512
--run_only "Lut3DRenderer/avx512_tetrahedral_bounds")
endif()
else()
add_ocio_test_variant(${TEST_NAME} ${TEST_BINARY})
Expand Down
92 changes: 92 additions & 0 deletions tests/cpu/ops/lut3d/Lut3DOpCPU_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,95 @@ OCIO_ADD_TEST(Lut3DRenderer, nan_tetra_test)
Lut3DRendererNaNTest(OCIO::INTERP_TETRAHEDRAL);
}

#if OCIO_USE_AVX512 && defined(_WIN32)

#include "ops/lut3d/Lut3DOpCPU_AVX512.h"
#include <cstring>
#include <windows.h>

namespace
{
// Places a buffer so its last byte is immediately followed by a PAGE_NOACCESS page, so
// any read or write past the requested size raises an access violation right away
// instead of only sometimes, depending on heap layout.
class GuardedBuffer
{
public:
explicit GuardedBuffer(size_t numFloats)
{
const size_t sizeBytes = numFloats * sizeof(float);
const size_t pageSize = 4096;
const size_t dataPages = (sizeBytes + pageSize - 1) / pageSize;

m_base = static_cast<uint8_t *>(VirtualAlloc(nullptr, (dataPages + 1) * pageSize,
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
OCIO_REQUIRE_ASSERT(m_base);

DWORD oldProtect = 0;
const BOOL ok = VirtualProtect(m_base + dataPages * pageSize, pageSize,
PAGE_NOACCESS, &oldProtect);
OCIO_REQUIRE_ASSERT(ok);

m_ptr = reinterpret_cast<float *>(m_base + dataPages * pageSize - sizeBytes);
memset(m_ptr, 0, sizeBytes);
}

~GuardedBuffer()
{
VirtualFree(m_base, 0, MEM_RELEASE);
}

GuardedBuffer(const GuardedBuffer &) = delete;
GuardedBuffer & operator=(const GuardedBuffer &) = delete;

float * get() { return m_ptr; }

private:
uint8_t * m_base = nullptr;
float * m_ptr = nullptr;
};
} // anonymous namespace

// Diagnostic test for the "illegal instruction" crash seen in
// OpOptimizers/invlut_pair_identities on the windows-2025-vs2026 CI runner (not
// reproduced on other Windows configurations so far). Exercises the AVX512 tetrahedral
// LUT3D interpolation directly, sweeping pixel counts across the 16-lane boundary (to
// separate the masked "remainder" path from the main loop) and both a tiny grid (2,
// matching tests/data/files/lut_inv_pairs.ctf) and a normal-sized one (32), with every
// buffer (LUT, source, destination) placed against a guard page. Any out-of-bounds
// access, regardless of mechanism, will raise a clean, immediate access violation
// naming the exact (dim, numPixels) combination instead of an unexplained crash.
OCIO_ADD_TEST(Lut3DRenderer, avx512_tetrahedral_bounds)
{
if (!OCIO::CPUInfo::instance().hasAVX512()) throw SkipException();

for (int dim : { 2, 32 })
{
const int lutFloats = dim * dim * dim * 4;
GuardedBuffer lut(lutFloats);
float * lutPtr = lut.get();
for (int i = 0; i < lutFloats; ++i)
{
lutPtr[i] = static_cast<float>(i % 7) / 7.0f;
}

for (int numPixels = 1; numPixels <= 33; ++numPixels)
{
std::cerr << "avx512_tetrahedral_bounds: dim=" << dim
<< " numPixels=" << numPixels << std::endl;

GuardedBuffer src(numPixels * 4);
GuardedBuffer dst(numPixels * 4);
float * srcPtr = src.get();
for (int i = 0; i < numPixels * 4; ++i)
{
srcPtr[i] = static_cast<float>(i % 5) / 5.0f;
}

OCIO::applyTetrahedralAVX512(lut.get(), dim, src.get(), dst.get(), numPixels);
}
}
}

#endif // OCIO_USE_AVX512 && defined(_WIN32)

Loading