Add custom viewport color correction (sRGB/OCIO), bypassing HdxColorCorrectionTask

Hydra's HdxColorCorrectionTask rendered prims black in OCIO mode and could
corrupt the GlfDrawTarget bind stack on failure (skipping Unbind), blacking
out every later frame including sRGB. Replace it with our own GL post-process:
the scene renders linear (RGBA16F) and is corrected by a fullscreen shader --
linear->sRGB encode, or OCIO via the OCIO 2.1 GPU API (GpuShaderDesc plus
uploaded 1D/3D LUT textures). OCIO build failures fall back to sRGB (never
black) and USD diagnostics are routed to the app log.

- core: ViewportColorCorrector + ApplyViewportColorCorrection in UsdSceneRenderer
- utils: OcioConfigParser enumerates displays/views/colorspaces/looks from $OCIO
- ui: gear-menu OCIO controls (ViewportTile) + per-viewport persistence (ViewportPanel)
- Application: point $OCIO at the bundled ACES 1.2 config
- CMake: link/copy OpenColorIO, download ACES 1.2 config; plus hdCycles build
  config (disable OpenVDB/Embree, fix TBB/OpenSubdiv/Imath dirs, exclude CRT DLLs)
- main: pre-flight plugin DLL load check to skip plugins with missing deps

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-27 17:10:44 +08:00
parent 8316e419ba
commit fb1ae9d3a6
12 changed files with 872 additions and 23 deletions
+120 -10
View File
@@ -16,6 +16,12 @@ find_package(Imgui REQUIRED)
find_package(Glad REQUIRED)
find_package(FFmpeg REQUIRED)
# OpenColorIO — provided by the OpenUSD distribution (USD built with OCIO support)
set(OpenColorIO_DIR
"${OpenUSD_ROOT_DIR}/lib/cmake/OpenColorIO"
CACHE PATH "OpenColorIO CMake config dir" FORCE)
find_package(OpenColorIO CONFIG REQUIRED)
# USD build that includes hdEmbree (built with PXR_ENABLE_EMBREE_PLUGIN=ON).
# Can be a separate install from OpenUSD_ROOT_DIR; leave empty to search there instead.
set(HDEMBREE_USD_ROOT "" CACHE PATH "USD build containing hdEmbree plugin (separate from OpenUSD_ROOT_DIR)")
@@ -123,6 +129,13 @@ if(WITH_CYCLES)
-DWITH_CYCLES_DEVICE_HIP=OFF
-DWITH_CYCLES_DEVICE_ONEAPI=OFF
-DWITH_CYCLES_LOGGING=OFF
# USD ships OpenVDB v9; Cycles prebuilt is v13 — ABI mismatch, both named
# openvdb.dll. Disable openvdb in Cycles to avoid the version conflict.
-DWITH_CYCLES_OPENVDB=OFF
# Embree4 links tbb12.dll; USD already loads tbb.dll at process startup.
# oneTBB detects the older tbb.dll and aborts initialization (DLL_INIT_FAILED).
# Disable Embree so Cycles uses its own BVH traversal instead.
-DWITH_CYCLES_EMBREE=OFF
# ---- pxrConfig.cmake dependency overrides ----
# pxrConfig.cmake runs find_dependency() for these before Cycles'
# precompiled lib paths are on CMAKE_PREFIX_PATH, so we must supply
@@ -131,12 +144,17 @@ if(WITH_CYCLES)
-DPython3_EXECUTABLE=$ENV{LOCALAPPDATA}/Programs/Python/Python312/python.exe
-DPython3_LIBRARY=$ENV{LOCALAPPDATA}/Programs/Python/Python312/libs/python312.lib
-DPython3_INCLUDE_DIR=$ENV{LOCALAPPDATA}/Programs/Python/Python312/include
-DTBB_DIR=${OpenUSD_ROOT_DIR}/lib/cmake/TBB
-DTBB_DIR=${CMAKE_SOURCE_DIR}/third_party/cycles/lib/windows_x64/tbb/lib/cmake/TBB
-DMaterialX_DIR=${OpenUSD_ROOT_DIR}/lib/cmake/MaterialX
# Our USD install has no standalone OpenSubdiv/Imath cmake packages
# (they're linked into the USD DLLs); skip those find_dependency calls.
-DPXR_FIND_OPENSUBDIV_IN_CONFIG=OFF
-DPXR_FIND_IMATH_IN_CONFIG=OFF
# OpenSubdiv and Imath cmake configs are bundled in the USD install.
# We must supply their dirs so pxrTargets.cmake can resolve the imported targets.
-DOpenSubdiv_DIR=${OpenUSD_ROOT_DIR}/lib/cmake/OpenSubdiv
-DImath_DIR=${OpenUSD_ROOT_DIR}/lib/cmake/Imath
# Force Cycles to use its own prebuilt OCIO 2.5, not the OCIO 2.1
# bundled in the new USD include dir. Without this, the new USD's
# include/OpenColorIO/ (OCIO 2.1) shadows Cycles' prebuilt OCIO 2.5
# headers and the colorspace.cpp API calls fail to compile.
-DOpenColorIO_DIR=${CMAKE_SOURCE_DIR}/third_party/cycles/lib/windows_x64/opencolorio/lib/cmake/OpenColorIO
BUILD_COMMAND
${CMAKE_COMMAND} --build <BINARY_DIR> --config Release
INSTALL_COMMAND
@@ -179,6 +197,7 @@ target_link_libraries(UsdLayerManager PRIVATE
Imgui::Imgui
Glad::Glad
FFmpeg::FFmpeg
OpenColorIO::OpenColorIO
ole32
shell32
)
@@ -202,6 +221,14 @@ if(WIN32)
_CRT_SECURE_NO_WARNINGS
)
# OpenColorIO DLL — copy from USD bin/ (which already ships OpenColorIO_2_1.dll)
add_custom_command(TARGET UsdLayerManager POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${OpenUSD_ROOT_DIR}/bin/OpenColorIO_2_1.dll"
"$<TARGET_FILE_DIR:UsdLayerManager>"
COMMENT "Copying OpenColorIO runtime DLL..."
)
# FFmpeg DLLs — copy all .dll files from third_party/ffmpeg/bin
file(GLOB FFMPEG_RUNTIME_DLLS "${CMAKE_SOURCE_DIR}/third_party/ffmpeg/bin/*.dll")
if(FFMPEG_RUNTIME_DLLS)
@@ -213,6 +240,26 @@ if(WIN32)
)
endif()
# cmake -P script to copy USD bin/ DLLs excluding CRT DLLs (msvcp, vcruntime, etc.).
# The USD distribution bundles older CRT DLLs (14.34) that conflict with Cycles
# binaries built against the newer system CRT (14.42+). The system CRT is
# always present on Windows 10+ — no need to bundle our own copy.
file(WRITE "${CMAKE_BINARY_DIR}/copy_usd_bin_dlls.cmake"
"file(GLOB _all_dlls \"${OpenUSD_ROOT_DIR}/bin/*.dll\")\n"
"set(_dlls)\n"
"foreach(_dll \${_all_dlls})\n"
" get_filename_component(_name \"\${_dll}\" NAME)\n"
" string(TOLOWER \"\${_name}\" _lname)\n"
" if(_lname MATCHES \"^(msvcp|vcruntime|ucrtbase|concrt|api-ms-win-)\")\n"
" continue()\n"
" endif()\n"
" list(APPEND _dlls \"\${_dll}\")\n"
"endforeach()\n"
"if(_dlls)\n"
" file(COPY \${_dlls} DESTINATION \"\${DEST_DIR}\")\n"
"endif()\n"
)
# Copy runtime DLLs to output directory for each configuration
add_custom_command(TARGET UsdLayerManager POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:UsdLayerManager>"
@@ -220,10 +267,10 @@ if(WIN32)
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${OpenUSD_BIN_DIR}"
"$<TARGET_FILE_DIR:UsdLayerManager>"
# OpenUSD bin/ — tbb.dll, MaterialX, OpenEXR, OpenImageIO, etc.
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${OpenUSD_ROOT_DIR}/bin"
"$<TARGET_FILE_DIR:UsdLayerManager>"
# OpenUSD bin/ — tbb.dll, MaterialX, OpenEXR, OpenImageIO, etc. (CRT DLLs excluded)
COMMAND ${CMAKE_COMMAND}
"-DDEST_DIR=$<TARGET_FILE_DIR:UsdLayerManager>"
-P "${CMAKE_BINARY_DIR}/copy_usd_bin_dlls.cmake"
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${OpenUSD_ROOT_DIR}/lib/usd"
"$<TARGET_FILE_DIR:UsdLayerManager>/usd"
@@ -307,9 +354,16 @@ if(WIN32)
"foreach(_dll \${_all_dlls})\n"
" get_filename_component(_name \"\${_dll}\" NAME)\n"
" string(TOLOWER \"\${_name}\" _lname)\n"
# Exclude CRT DLLs (system must supply these; Cycles bundles an older version).
" if(_lname MATCHES \"^(msvcp|vcruntime|ucrtbase|concrt|api-ms-win-)\")\n"
" continue()\n"
" endif()\n"
# Exclude debug-variant DLLs (not needed in release, just wasted space).
# Pattern: OpenColorIO_d_2_5.dll → contains "_d_"
# openjph.0.25d.dll → ends with "d.dll"
" if(_lname MATCHES \"_d_\" OR _lname MATCHES \"d[.]dll$\")\n"
" continue()\n"
" endif()\n"
" list(APPEND _dlls \"\${_dll}\")\n"
"endforeach()\n"
"if(_dlls)\n"
@@ -355,10 +409,17 @@ install(DIRECTORY ${OpenUSD_BIN_DIR}/
)
# Install OpenUSD bin/ DLLs — tbb.dll, tbbmalloc.dll, MaterialX, OpenEXR,
# OpenImageIO, zlib, etc. These are separate from lib/ and also required at runtime.
# OpenImageIO, zlib, etc. Exclude CRT DLLs: the system VC++ Redistributable supplies
# these at runtime; bundling an older copy (14.34) causes crashes on machines with
# Cycles or other DLLs compiled against the newer CRT (14.42+).
install(DIRECTORY ${OpenUSD_ROOT_DIR}/bin/
DESTINATION bin
FILES_MATCHING PATTERN "*.dll"
PATTERN "msvcp*" EXCLUDE
PATTERN "vcruntime*" EXCLUDE
PATTERN "ucrtbase*" EXCLUDE
PATTERN "concrt*" EXCLUDE
PATTERN "api-ms-win-*" EXCLUDE
)
install(DIRECTORY ${OpenUSD_ROOT_DIR}/lib/usd
@@ -435,6 +496,8 @@ if(OPENUSD_HAS_CYCLES)
PATTERN "VCRUNTIME140*.dll" EXCLUDE
PATTERN "ucrtbase*.dll" EXCLUDE
PATTERN "api-ms-win-*.dll" EXCLUDE
PATTERN "OpenColorIO_d_*.dll" EXCLUDE # debug OCIO build
PATTERN "openjph.*d.dll" EXCLUDE # debug OpenJPH
)
# tbb12.dll (used by openvdb/embree4) lives in the precompiled lib tree, not install output
install(FILES "${CYCLES_TBB12_DLL}"
@@ -485,6 +548,35 @@ if(PYTHON311_DLL)
)
endif()
# ---------------------------------------------------------------------------
# OCIO: download ACES 1.2 config at configure time if not present
# ---------------------------------------------------------------------------
set(_ocio_config_dir "${CMAKE_SOURCE_DIR}/resources/OpenColorIO-Configs/aces_1.2")
if(NOT EXISTS "${_ocio_config_dir}/config.ocio")
message(STATUS "Downloading ACES 1.2 OCIO config (~124 MB) ...")
set(_ocio_zip "${CMAKE_BINARY_DIR}/aces_1.2.zip")
file(DOWNLOAD
"https://github.com/colour-science/OpenColorIO-Configs/releases/download/v1.2/OpenColorIO-Config-ACES-1.2.zip"
"${_ocio_zip}"
SHOW_PROGRESS
STATUS _ocio_dl_status
)
list(GET _ocio_dl_status 0 _ocio_dl_code)
if(_ocio_dl_code EQUAL 0)
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xf "${_ocio_zip}"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
)
file(COPY "${CMAKE_BINARY_DIR}/OpenColorIO-Config-ACES-1.2/aces_1.2/"
DESTINATION "${_ocio_config_dir}")
file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/OpenColorIO-Config-ACES-1.2")
file(REMOVE "${_ocio_zip}")
message(STATUS "ACES 1.2 OCIO config installed to ${_ocio_config_dir}")
else()
message(WARNING "ACES 1.2 OCIO download failed (${_ocio_dl_status}) — OCIO will not be bundled.")
endif()
endif()
# Copy resources to build directory
file(COPY ${CMAKE_SOURCE_DIR}/resources
DESTINATION ${CMAKE_BINARY_DIR}
@@ -503,6 +595,24 @@ add_custom_command(TARGET UsdLayerManager POST_BUILD
COMMENT "Copying fonts and SVG icons to build output"
)
# Copy ACES OCIO config to build output — only on first build (skipped if already present).
if(EXISTS "${_ocio_config_dir}/config.ocio")
add_custom_command(TARGET UsdLayerManager POST_BUILD
COMMAND ${CMAKE_COMMAND}
"-DSRC=${_ocio_config_dir}"
"-DDST=$<TARGET_FILE_DIR:UsdLayerManager>/resources/OpenColorIO-Configs/aces_1.2"
-P "${CMAKE_SOURCE_DIR}/cmake/CopyDirIfMissing.cmake"
COMMENT "Copying ACES OCIO config to build output (first time only)"
)
endif()
# Install OpenColorIO DLL (from the OpenUSD distribution's bin/)
install(FILES
"${OpenUSD_ROOT_DIR}/bin/OpenColorIO_2_1.dll"
DESTINATION bin
OPTIONAL
)
# Install resources (icons, fonts placeholder) next to the exe so the
# exe-relative path "resources/..." resolves correctly from install/bin/.
install(DIRECTORY ${CMAKE_SOURCE_DIR}/resources