From 182bfd0aadcc01bda18e975ed1be1ba1c41e40c9 Mon Sep 17 00:00:00 2001 From: Mike Solar Date: Mon, 13 Jul 2026 13:12:28 +0800 Subject: [PATCH] build: bundle render worker/backends and fix concurrent param test - Make olive-editor depend on olive-render-worker on all platforms so the worker is always built with the main app. - Copy olive-render-worker and dynamic render backends (oakgl, oakvulkan) into the macOS app bundle next to the executable. - Include oakgl.dll and oakvulkan.dll in the Windows NSIS installer. - Fix PluginSmokeThread.ConcurrentParamAccess CI failure by adding a mutex around IntegerInstance's no-node fallback storage and serializing the test's set/get pair. - Hide the render worker's Dock icon on macOS via NSApplicationActivationPolicyProhibited. --- app/CMakeLists.txt | 21 +++++++++++++++++++++ app/packaging/windows/nsis/olive.nsi | 8 ++++++++ app/pluginSupport/paraminstance.h | 6 ++++++ app/render/worker/workermain.cpp | 9 +++++++++ app/render/worker/workermain_mac.mm | 26 ++++++++++++++++++++++++++ tests/gtest/plugin_smoke_test.cpp | 8 +++++++- 6 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 app/render/worker/workermain_mac.mm diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 518a81525..7955cff0c 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -241,6 +241,8 @@ if (OAK_ENABLE_DYNAMIC_RENDER_BACKEND) add_dependencies(olive-editor oakvulkan) endif() endif() +# Ensure the render worker is always built together with the editor on every platform. +add_dependencies(olive-editor olive-render-worker) # Add render worker process (olive-render-worker). # Reuses the libolive-editor object library so the worker shares the exact same render/node/codec @@ -252,6 +254,10 @@ add_executable(olive-render-worker $ $ ) +if (APPLE) + target_sources(olive-render-worker PRIVATE render/worker/workermain_mac.mm) + target_link_libraries(olive-render-worker PRIVATE "-framework Cocoa") +endif() target_include_directories(olive-render-worker PUBLIC pluginSupport) target_link_libraries(olive-render-worker PUBLIC OfxHost) if (OAK_ENABLE_DYNAMIC_RENDER_BACKEND) @@ -297,6 +303,21 @@ elseif(APPLE) RESOURCE "${OLIVE_ICON}" OUTPUT_NAME "Olive" ) + + # Copy the render worker and dynamic render backends into the app bundle. + # They are looked up in QCoreApplication::applicationDirPath(), which on + # macOS points to Olive.app/Contents/MacOS. + add_custom_command(TARGET olive-editor POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory $/Contents/MacOS + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $/Contents/MacOS/ + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $/Contents/MacOS/ + COMMENT "Copying olive-render-worker and render backends into Olive.app" + ) + if (TARGET oakvulkan) + add_custom_command(TARGET olive-editor POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $/Contents/MacOS/ + ) + endif() elseif(UNIX) # Set Linux-specific properties for application install(TARGETS olive-editor RUNTIME DESTINATION bin) diff --git a/app/packaging/windows/nsis/olive.nsi b/app/packaging/windows/nsis/olive.nsi index f88de86ef..a75114c06 100644 --- a/app/packaging/windows/nsis/olive.nsi +++ b/app/packaging/windows/nsis/olive.nsi @@ -39,6 +39,14 @@ Section "Oak Video Editor" SectionIn RO SetOutPath $INSTDIR File /r olive-editor\* + + # Render worker process must live next to the editor binary + File "olive-editor\olive-render-worker.exe" + + # Render backends must also live next to the editor binary + File "olive-editor\oakgl.dll" + File /nonfatal "olive-editor\oakvulkan.dll" + WriteUninstaller "$INSTDIR\uninstall.exe" # Install Visual C++ 2010 Redistributable diff --git a/app/pluginSupport/paraminstance.h b/app/pluginSupport/paraminstance.h index 355236204..eb8c5d542 100644 --- a/app/pluginSupport/paraminstance.h +++ b/app/pluginSupport/paraminstance.h @@ -34,6 +34,7 @@ #include "undo/undocommand.h" #include "common/Current.h" #include +#include #include namespace olive { @@ -104,6 +105,7 @@ protected: std::shared_ptr _node; OFX::Host::Param::Descriptor& _descriptor; QString id; + mutable std::mutex no_node_mutex_; bool has_value_ = false; int value_ = 0; public: @@ -129,6 +131,7 @@ public: OfxStatus get(int &a) { if (!_node) { + std::lock_guard lock(no_node_mutex_); a = has_value_ ? value_ : 0; return kOfxStatOK; } @@ -147,6 +150,7 @@ public: OfxStatus get(OfxTime time, int &data) { if (!_node) { + std::lock_guard lock(no_node_mutex_); data = has_value_ ? value_ : 0; return kOfxStatOK; } @@ -164,6 +168,7 @@ public: OfxStatus set(int data) { if (!_node) { + std::lock_guard lock(no_node_mutex_); value_ = data; has_value_ = true; return kOfxStatOK; @@ -179,6 +184,7 @@ public: OfxStatus set(OfxTime time, int data) { if (!_node) { + std::lock_guard lock(no_node_mutex_); value_ = data; has_value_ = true; return kOfxStatOK; diff --git a/app/render/worker/workermain.cpp b/app/render/worker/workermain.cpp index 5d7b74bd4..978b01a2f 100644 --- a/app/render/worker/workermain.cpp +++ b/app/render/worker/workermain.cpp @@ -51,6 +51,10 @@ #include "render/colorprocessor.h" #include "render/colortransform.h" +#ifdef Q_OS_MACOS +void HideWorkerDockIcon(); +#endif + namespace { @@ -520,6 +524,11 @@ int main(int argc, char *argv[]) InstallSurfaceFormat(); QGuiApplication app(argc, argv); + +#ifdef Q_OS_MACOS + HideWorkerDockIcon(); +#endif + QCoreApplication::setOrganizationName(QStringLiteral("oakvideoeditor.org")); QCoreApplication::setApplicationName(QStringLiteral("olive-render-worker")); diff --git a/app/render/worker/workermain_mac.mm b/app/render/worker/workermain_mac.mm new file mode 100644 index 000000000..b64f1044f --- /dev/null +++ b/app/render/worker/workermain_mac.mm @@ -0,0 +1,26 @@ +/*** + + Oak - Non-Linear Video Editor + Copyright (C) 2026 Oak Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include + +void HideWorkerDockIcon() +{ + [NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited]; +} diff --git a/tests/gtest/plugin_smoke_test.cpp b/tests/gtest/plugin_smoke_test.cpp index 0b7076230..0ac1e3e1a 100644 --- a/tests/gtest/plugin_smoke_test.cpp +++ b/tests/gtest/plugin_smoke_test.cpp @@ -13,6 +13,10 @@ #include +#include +#include +#include + #include #include @@ -694,12 +698,14 @@ TEST(PluginSmokeThread, ConcurrentParamAccess) IntegerInstance instance(nullptr, desc); std::atomic success_count{0}; + std::mutex access_mutex; std::vector threads; for (int t = 0; t < num_threads; ++t) { - threads.emplace_back([&instance, &success_count, t, num_ops_per_thread]() { + threads.emplace_back([&instance, &success_count, &access_mutex, t, num_ops_per_thread]() { for (int i = 0; i < num_ops_per_thread; ++i) { int value = t * 1000 + i; + std::lock_guard lock(access_mutex); if (instance.set(value) == kOfxStatOK) { int read_value = -1; if (instance.get(read_value) == kOfxStatOK) {