diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bf86f8..6eec5a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,14 +60,96 @@ if(HDARNOLD_ROOT AND EXISTS "${HDARNOLD_ROOT}/plugin/hdArnold.dll") set(NDRARNOLD_PLUGIN_DIR "${HDARNOLD_ROOT}/plugin/ndrArnold") if(ARNOLD_LOCATION AND EXISTS "${ARNOLD_LOCATION}/bin/ai.dll") set(ARNOLD_AI_DLL "${ARNOLD_LOCATION}/bin/ai.dll") + # ai.dll also requires companion runtime DLLs (OIDN denoiser, Adsk licensing, cer) + file(GLOB ARNOLD_RUNTIME_DLLS + "${ARNOLD_LOCATION}/bin/ai*.dll" + "${ARNOLD_LOCATION}/bin/AdClm*.dll" + "${ARNOLD_LOCATION}/bin/AdskLicensing*.dll" + "${ARNOLD_LOCATION}/bin/cer.dll" + ) else() set(ARNOLD_AI_DLL "") + set(ARNOLD_RUNTIME_DLLS "") endif() else() set(OPENUSD_HAS_ARNOLD FALSE) message(STATUS "hdArnold: NOT found — set HDARNOLD_ROOT to the arnold-usd install dir and ARNOLD_LOCATION to the MtoA root") endif() +# ── Cycles hdCycles Hydra render delegate ──────────────────────────────────── +# Build Blender Cycles from third_party/cycles using ExternalProject. +# Set WITH_CYCLES=ON to enable; requires MSVC, and uses the precompiled libs +# bundled in third_party/cycles/lib/windows_x64/. +# hdCycles.dll is deployed to usd/ alongside hdEmbree and hdArnold. +option(WITH_CYCLES "Build Cycles Hydra render delegate from third_party/cycles" OFF) + +set(CYCLES_BINARY_DIR "${CMAKE_BINARY_DIR}/cycles_build") +set(CYCLES_INSTALL_DIR "${CMAKE_BINARY_DIR}/cycles_install") +set(HDCYCLES_DLL "${CYCLES_INSTALL_DIR}/hydra/hdCycles.dll") +set(HDCYCLES_PLUGIN_DIR "${CYCLES_INSTALL_DIR}/hydra/hdCycles") +# tbb12.dll is required by openvdb/embree4 but lives in the precompiled lib tree, +# not in the install output — deploy it explicitly. +set(CYCLES_TBB12_DLL "${CMAKE_SOURCE_DIR}/third_party/cycles/lib/windows_x64/tbb/bin/tbb12.dll") + +if(WITH_CYCLES) + include(ExternalProject) + + # Resolve absolute USD root so we can forward it to the sub-build. + # FindOpenUSD.cmake stores the path in OpenUSD_ROOT_DIR. + if(NOT OpenUSD_ROOT_DIR) + message(FATAL_ERROR "WITH_CYCLES requires OpenUSD_ROOT_DIR to be set (run find_package(OpenUSD) first).") + endif() + + ExternalProject_Add(CyclesBuild + SOURCE_DIR "${CMAKE_SOURCE_DIR}/third_party/cycles" + BINARY_DIR "${CYCLES_BINARY_DIR}" + INSTALL_DIR "${CYCLES_INSTALL_DIR}" + CMAKE_ARGS + # Always Release — Cycles' Debug build is slow and rarely needed here. + -DCMAKE_BUILD_TYPE=Release + -DCMAKE_INSTALL_PREFIX= + # Point Cycles at our app's USD so hdCycles is ABI-compatible. + -DPXR_ROOT=${OpenUSD_ROOT_DIR} + # Hydra delegate is the only deliverable we need. + -DWITH_CYCLES_HYDRA_RENDER_DELEGATE=ON + -DWITH_CYCLES_USD=ON + # Use bundled precompiled libs from lib/windows_x64/. + -DWITH_LIBS_PRECOMPILED=ON + # Turn off heavy optional features that aren't needed for the delegate. + -DWITH_CYCLES_STANDALONE_GUI=OFF + -DWITH_CYCLES_DEVICE_CUDA=OFF + -DWITH_CYCLES_DEVICE_OPTIX=OFF + -DWITH_CYCLES_DEVICE_HIP=OFF + -DWITH_CYCLES_DEVICE_ONEAPI=OFF + -DWITH_CYCLES_LOGGING=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 + # them explicitly. The Python3 vars also override the hardcoded + # CI build-machine path embedded in pxrConfig.cmake. + -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 + -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 + BUILD_COMMAND + ${CMAKE_COMMAND} --build --config Release + INSTALL_COMMAND + ${CMAKE_COMMAND} --install --config Release + BUILD_BYPRODUCTS + "${HDCYCLES_DLL}" + ) + + set(OPENUSD_HAS_CYCLES TRUE) +else() + set(OPENUSD_HAS_CYCLES FALSE) + message(STATUS "hdCycles: disabled — set WITH_CYCLES=ON to build from third_party/cycles") +endif() + # Collect source files file(GLOB_RECURSE CORE_SOURCES "src/core/*.cpp") file(GLOB_RECURSE UI_SOURCES "src/ui/*.cpp") @@ -97,6 +179,12 @@ target_link_libraries(UsdLayerManager PRIVATE Glad::Glad ) +# Cycles is an ExternalProject; UsdLayerManager must wait for it to finish +# before POST_BUILD copies hdCycles.dll to the output directory. +if(WITH_CYCLES) + add_dependencies(UsdLayerManager CyclesBuild) +endif() + # Platform-specific settings if(WIN32) # Windows-specific settings @@ -171,15 +259,61 @@ if(WIN32) "$/usd/ndrArnold" COMMENT "Copying hdArnold plugin..." ) - if(ARNOLD_AI_DLL) + if(ARNOLD_RUNTIME_DLLS) add_custom_command(TARGET UsdLayerManager POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${ARNOLD_AI_DLL}" + ${ARNOLD_RUNTIME_DLLS} "$" - COMMENT "Copying Arnold runtime ai.dll..." + COMMENT "Copying Arnold runtime DLLs (ai, OIDN, licensing)..." ) endif() endif() + + if(OPENUSD_HAS_CYCLES) + # hdCycles uses the same usd/ layout as hdEmbree: + # usd/hdCycles.dll + usd/hdCycles/resources/plugInfo.json + # The bundled plugInfo.json has Root=".." and LibraryPath="../hdCycles.dll" + # which resolves correctly once the plugin dir lives in usd/. + # + # Runtime deps (embree4, epoxy, imath, openvdb, OIDN, sycl, vulkan, etc.) + # live in CYCLES_INSTALL_DIR root and must be next to the exe. We can't + # file(GLOB) them at configure time (ExternalProject hasn't run yet), so we + # write a small cmake -P script that globs them at build time instead. + # The script runs at build time (after ExternalProject finishes) so it can glob + # the actual install output. CRT/Windows DLLs are excluded — they must come + # from the system or the main exe's toolchain, not from Cycles' bundled copy. + file(WRITE "${CMAKE_BINARY_DIR}/copy_cycles_runtime_dlls.cmake" + "file(GLOB _all_dlls \"${CYCLES_INSTALL_DIR}/*.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" + ) + add_custom_command(TARGET UsdLayerManager POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${HDCYCLES_DLL}" + "$/usd/hdCycles.dll" + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${HDCYCLES_PLUGIN_DIR}" + "$/usd/hdCycles" + COMMAND ${CMAKE_COMMAND} + "-DDEST_DIR=$" + -P "${CMAKE_BINARY_DIR}/copy_cycles_runtime_dlls.cmake" + # tbb12.dll is required by openvdb/embree4 but is not in the install output + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CYCLES_TBB12_DLL}" + "$/tbb12.dll" + COMMENT "Copying hdCycles plugin and runtime DLLs..." + ) + endif() endif() # Compiler warnings @@ -251,14 +385,36 @@ if(OPENUSD_HAS_ARNOLD) DESTINATION bin/usd OPTIONAL ) - if(ARNOLD_AI_DLL) - install(FILES "${ARNOLD_AI_DLL}" + if(ARNOLD_RUNTIME_DLLS) + install(FILES ${ARNOLD_RUNTIME_DLLS} DESTINATION bin OPTIONAL ) endif() endif() +if(OPENUSD_HAS_CYCLES) + install(FILES "${HDCYCLES_DLL}" + DESTINATION bin/usd + OPTIONAL + ) + install(DIRECTORY "${HDCYCLES_PLUGIN_DIR}" + DESTINATION bin/usd + OPTIONAL + ) + # Cycles runtime deps (embree4, epoxy, imath, openvdb, OIDN, sycl, etc.) + install(DIRECTORY "${CYCLES_INSTALL_DIR}/" + DESTINATION bin + FILES_MATCHING PATTERN "*.dll" + OPTIONAL + ) + # tbb12.dll (used by openvdb/embree4) lives in the precompiled lib tree, not install output + install(FILES "${CYCLES_TBB12_DLL}" + DESTINATION bin + OPTIONAL + ) +endif() + # Install Python runtime DLLs required by OpenUSD. install(FILES "$ENV{LOCALAPPDATA}/Programs/Python/Python312/python312.dll" @@ -318,11 +474,17 @@ endif() message(STATUS "hdArnold support: ${OPENUSD_HAS_ARNOLD}") if(OPENUSD_HAS_ARNOLD) message(STATUS "hdArnold DLL: ${HDARNOLD_DLL}") - message(STATUS "Arnold ai.dll: ${ARNOLD_AI_DLL}") + message(STATUS "Arnold runtime DLLs: ${ARNOLD_RUNTIME_DLLS}") if(NOT ARNOLD_AI_DLL) message(WARNING "hdArnold found but ai.dll not located — set ARNOLD_LOCATION to the MtoA root (e.g. C:/Autodesk/mtoa/5.5.0/2026)") endif() endif() +message(STATUS "hdCycles support: ${OPENUSD_HAS_CYCLES}") +if(OPENUSD_HAS_CYCLES) + message(STATUS "Cycles source: ${CMAKE_SOURCE_DIR}/third_party/cycles") + message(STATUS "Cycles build: ${CYCLES_BINARY_DIR}") + message(STATUS "Cycles install: ${CYCLES_INSTALL_DIR}") +endif() message(STATUS "=======================================") message(STATUS "") diff --git a/CMakePresets.json b/CMakePresets.json index 8aceeb3..51be5bc 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -13,7 +13,11 @@ "IMGUI_DIR": "${sourceDir}/third_party/imgui-1.92.7", "CMAKE_CXX_STANDARD": "17", "CMAKE_CXX_STANDARD_REQUIRED": "ON", - "BUILD_TESTS": "ON" + "BUILD_TESTS": "ON", + "WITH_CYCLES": "ON", + "HDARNOLD_ROOT": "E:/library/hdArnold", + "ARNOLD_LOCATION": "C:/Autodesk/mtoa/5.5.0/2026", + "HDEMBREE_USD_ROOT": "E:/USD_v25.05_embree" } }, {