Commit Graph
1032 Commits
Author SHA1 Message Date
Mike-Solar f0d41eae52 build: rebrand output artifacts to Oak and fix macOS QML deployment
- Rename macOS bundle output from Olive.app to Oak.app.
- Rename editor binary to oak-editor and render worker to oak-render-worker.
- Rename crash handler output to oak-crashhandler.
- Update worker lookup, NSIS installer, Linux desktop/AppRun, crashhandler
  symbol paths, and documentation for the new binary names.
- Update CD workflow paths and add -qmldir flags to macdeployqt so QtQuick
  / QML plugins required by KDDockWidgets are bundled, fixing the launch
  crash on macOS.
- Update user-facing GitHub URLs to OakVideoEditorCommunity/oak.
2026-07-13 15:26:15 +08:00
Mike-Solar ea78558a31 render: reference-count graph snapshots to prevent premature deletion
Proxy generation modifies the project, causing graph snapshots to be
rewritten. The old implementation deleted the previous snapshot
immediately, even though queued render jobs still held its path. The
worker then failed to load the deleted file.

Add per-path reference counting:
- Increment when a job is created with a snapshot path.
- Decrement when the job is processed, cancelled or removed.
- Only delete a snapshot when its reference count reaches zero and it
  is no longer the cached snapshot for the project.

Also keep snapshots in the system temp directory as before, since the
location itself was not the bug.
2026-07-13 13:43:20 +08:00
Mike-Solar 8580542ac7 render: write graph snapshots to AppLocalData instead of system temp
The worker process on macOS could not see the graph snapshot when it
was placed in /var/folders/.../T (likely sandbox/working-directory
visibility). Write snapshots to a 'render-graphs' subdirectory of the
application's persistent data location instead, which both the editor
and the worker can access on all platforms.
2026-07-13 13:29:55 +08:00
Mike-Solar 5a5ad3bc14 render: add diagnostics for worker graph load failures
- Report QFile::errorString() when ProjectSerializer::Load() fails to open
  the graph file, so the worker log shows why instead of an empty detail.
- In olive-render-worker LoadGraph(), check file existence, size and
  readability before delegating to the serializer and log the attempt.
2026-07-13 13:25:25 +08:00
Mike-Solar 182bfd0aad 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.
2026-07-13 13:12:28 +08:00
Mike-Solar e881bb049f Remove some logs 2026-07-13 10:29:02 +08:00
Mike-Solar 5c8f80480d UI: flatten preferences behavior tabs and add node parameter editor shortcut
- Move Behavior-General options (hover focus, slider ladder, scroll zooms)
  into the General preferences tab.
- Move Behavior-Audio option (audio scrubbing) into the Audio preferences tab.
- Promote remaining Behavior categories (Timeline, Playback, Project, Nodes,
  Rendering) to top-level sidebar entries without the 'Behavior - ' prefix.
- Update Chinese translations for the new sidebar titles and fill unfinished
  Behavior tab strings.

NodeView:
- Remove double-click jump-to-parameter-editor behavior; keep expand/collapse.
- Add right-click context menu item 'Show in Parameter Editor'.
- Add Shift+P shortcut bound to the same action.

Render:
- Fix crash in PreviewAutoCacher::ClearSingleFrameRenders when proxy playback
  causes a render ticket to finish synchronously before the watcher pointer is
  returned. Defer the watcher Finished signal via queued connection so the
  caller can safely register the watcher before it is deleted.
2026-07-13 10:19:30 +08:00
Mike-Solar 1f446f55b4 Cache color processors in render worker and canonicalize OCIO roles
ColorProcessor creation was done for every exported frame and the input
reference space was passed as a role string (e.g. "scene_linear"). If
getProcessor() rejected the role name the worker would crash, the pool
would retry the frame, and export throughput would drop to near zero with
minimal CPU/GPU usage.

- Canonicalize role names to colorspace names in ColorProcessor so
  "scene_linear" resolves to the config's actual colorspace.
- Wrap processor creation in a try/catch and initialize cpu_processor_ to
  nullptr on failure instead of dereferencing a null processor.
- Cache created ColorProcessor objects in the worker keyed by transform
  so OCIO processor/shader setup is only paid once per export.
2026-07-13 10:19:30 +08:00
Mike-Solar d66779d281 Apply export color transform in render worker
The export color transform was passed to RenderTask as a ColorProcessor,
but the worker IPC render_frame message never carried it. The worker
always set the ticket's coloroutput to null, so frames were returned in
the project's reference space and encoded without the chosen output
transform (e.g. Rec.709 / sRGB), causing the exported video to look
wrongly tinted.

Serialize the ColorTransform through the render_frame control message
and reconstruct the ColorProcessor on the worker side before rendering.
Also expose ColorTransform as a Qt metatype so it can be stored in a
ticket QVariant.
2026-07-13 10:19:30 +08:00
Mike-Solar ea37dc5da6 Prevent main-process crash when render worker dies during IPC write
When a render-worker process crashed or exited while the worker-pool
thread was writing a control message (e.g. right after an audio-sync and
drag operation triggered a new render), the main process received SIGPIPE
and terminated at WriteControlMessage().

- Ignore SIGPIPE in main() so QProcess can report the broken pipe through
  its normal error path instead of killing the application.
- Harden WriteControlMessage() / TryWriteControlMessage() to check the
  process state and the number of bytes written before waiting.
2026-07-13 10:19:30 +08:00
Mike-Solar 51ea3ca24e Use 10-bit packed preview format and add OCIO LUT regression tests
Renderer / preview:
- Switch the preview/display readback format from F16 to packed
  10-bit RGBA (PixelFormat::U10) to halve GPU->CPU/IPC bandwidth
  while keeping 10-bit panel precision.
- Add U10 support to VideoParams, FFmpeg/OIIO/OCIO utility mappings,
  OpenGL (GL_RGB10_A2), Vulkan (VK_FORMAT_A2B10G10R10_UNORM_PACK32),
  and plugin bit-depth lookups.
- Update preview autocacher comment to reflect the new behavior.

OCIO LUT tests:
- Add four E2E-style ColorLutNode gtests that drive a SolidGenerator
  -> OCIOLutNode graph through NodeTraverser and compare resulting
  pixels on the CPU. They cover forward/inverse transforms and verify
  that switching LUT direction and LUT file updates both the processor
  and the output pixels.

Cleanup:
- Remove a leftover SolidGenerator::Value debug fprintf.
- Capture render worker stderr in RenderWorkerFootageTest for better
  diagnostics.
2026-07-13 10:19:30 +08:00
Mike-Solar a7f7890db0 Use F16 for preview frames to halve GPU-to-CPU readback bandwidth 2026-07-13 10:19:30 +08:00
Mike-Solar e8443f8f8f Fix crash when toggling Use Proxy during playback and proxy generation output format 2026-07-13 10:19:30 +08:00
Mike-Solar 0969e2adc5 Add diagnostics for proxy toggle synchronization
Add temporary qDebug logging to Footage, ProjectCopier,
RenderWorkerPool, and TimelineWidget to trace why Use Proxy cannot be
 toggled and why proxy footage may still be used after disabling.
2026-07-13 10:19:30 +08:00
Mike-Solar 818b76b64e Sync Footage proxy state to render worker copy project
Proxy state (enabled/path/state/etc.) is stored as Footage member data,
not as a Node input, so ProjectCopier did not synchronize it to the
internal copy project used by worker processes. This caused toggling
Use Proxy in the UI to have no effect on rendered output.

Add a Footage::ProxySettingsChanged signal and have ProjectCopier sync
the proxy state to the copied Footage node, marking the copy project
modified so RenderWorkerPool writes a fresh graph snapshot.
2026-07-13 10:19:30 +08:00
Mike-Solar 94250a7690 Fix proxy decoding path and add proxy generation diagnostics
- RenderWorkerPool::DecodeInputFrame now uses the proxy filename/decoder/stream
  from FootageJob when a proxy is attached, so generated proxies are actually
  used during render.
- Add qDebug/qWarning logging to TimelineWidget::GenerateProxiesForSelectedClips
  and ProxyTask::Run to diagnose why Generate Proxy appears to do nothing.
2026-07-13 10:19:30 +08:00
Mike-Solar ca22028a52 Defer OCIO LUT processor generation in render worker and fix stale graph snapshots
- Override OCIOLutNode::Value() to ensure the processor is created/updated
  before the color transform job is emitted.
- In the worker process, mark the processor dirty on input/config changes
  instead of creating it synchronously during LoadGraph, which blocked the
  main process waiting for the graph load acknowledgement.
- Keep eager processor generation in the main GUI process so the viewer
  cache is invalidated immediately when the LUT file or direction changes.
- Mark the ProjectCopier's internal render-proxy project as modified when
  its update queue is processed, and reset the flag after RenderWorkerPool
  writes a new graph snapshot. This fixes the worker loading a stale graph
  snapshot after switching cube files or direction, which caused the old
  LUT effect to persist.

All existing tests pass.
2026-07-13 10:19:30 +08:00
Mike-Solar 68c0477715 Add hardware decoding support 2026-07-13 10:19:30 +08:00
Mike-Solar f6211f97a5 Fix render worker reuse and stabilize out-of-process video rendering 2026-07-13 10:19:30 +08:00
Mike-Solar 30e7153154 fix Windows and macOS symbol error 2026-07-13 10:19:30 +08:00
Mike-Solar e77de49406 add Comments 2026-07-13 10:19:30 +08:00
Mike-Solar 3c9592da45 完成Vulkan渲染后端 2026-07-13 10:19:30 +08:00
Mike-Solar e908786d43 Improve Vulkan Blit: caching, interpolation, swizzle, enable flags
- Cache a VkFramebuffer per texture to avoid creating/destroying one for
  every Blit() call.
- Create and cache both linear and nearest samplers; honor
  Texture::Interpolation in descriptor writes.
- Add single-channel image-view component swizzle (R -> RGB, A = 1) to
  match OpenGL grayscale behavior.
- Set texture-enable uniforms (NAME_enabled) when shaders declare them.
- Guard Blit() with null destination and emit a clear warning instead of
  recording an invalid render pass.

ctest passes 4/4 in both dynamic-backend ON and OFF builds.
2026-07-13 10:19:30 +08:00
Mike-Solar f4906862a1 Make Vulkan shader/UBO/layout path real enough for end-to-end blits
- Add shared UBO layout across vertex + fragment stages so vertex
  uniforms like ove_mvpmat compile and bind correctly.
- Rewrite uniform extraction/injection to avoid corrupting the UBO
  block and to keep explicit sampler bindings stable.
- Make the UBO and sampler descriptor bindings visible to both vertex
  and fragment stages.
- Add layout locations for vertex varyings (ove_texcoord) and fragment
  inputs so SPIR-V generation succeeds.
- Extend TransitionImageLayout() to cover all layout pairs used by
  upload/download/clear/blit.
- Add subpass dependencies to the cached render pass and leave
  destinations in SHADER_READ_ONLY_OPTIMAL after Blit().
- Move descriptor allocation before command recording and abort cleanly
  if allocation fails; switch Blit() to the persistent linear sampler.
- Add a gtest that creates a Vulkan backend, uploads a red U8 RGBA
  texture, blits through the default pass-through shader, and verifies
  the downloaded pixel is red. This test passes on the current system.

ctest passes 4/4; DynamicRenderBackend.* passes 3/1 (Vulkan fallback
skipped because Vulkan is available).
2026-07-13 10:19:30 +08:00
Mike-Solar f1d19a03f8 Harden Vulkan init/device selection and resource teardown
- Remove unconditional VK_KHR_swapchain request; offscreen renderer needs
  no device extensions, fixing failures on headless/CI setups.
- Enumerate physical devices properly and pick the first one with a
  graphics queue family instead of blindly choosing device 0.
- Check vkEnumeratePhysicalDevices/vkBindImageMemory/vkBindBufferMemory
  results.
- Validate FindMemoryType() result before allocation and log clear errors.
- Add a persistent linear sampler created in PostInit and destroy it in
  DestroyInternal.
- Fix DestroyInternal() early-return leak: now tears down the instance
  even if device creation failed.

ctest passes 4/4.
2026-07-13 10:19:30 +08:00
Mike-Solar 8b8aa945f0 Sync RenderManager::backend_ after DynamicRenderer fallback
DynamicRenderer::Load() can internally fall back from Vulkan to
OpenGL when the Vulkan library is missing or is_available() fails.
Previously RenderManager::backend_ stayed at kVulkan, so callers
asking RenderManager::backend() got the wrong answer. After a
successful dynamic load, sync backend_ from
DynamicRenderer::backend_name() and log any fallback.

ctest still passes 4/4 in build-default-on.
2026-07-13 10:19:29 +08:00
Mike-Solar b4e39e5bcd Address ChatGPT Vulkan review items
- Add PickRenderableFormat / IsColorAttachmentSupported so 3-channel
  Vulkan formats fall back to 4-channel when unsupported.
- Make oakvulkan target and C ABI check conditional on Vulkan_FOUND;
  skip liboakvulkan build/dependencies when Vulkan headers/libs are
  absent.
- Update Preferences tooltip to reflect Vulkan is an experimental
  prototype that may fall back to OpenGL.
- Revise dynamic backend plan doc: phase 3/4/5 described as prototype
  frameworks with runtime validation pending, and list recent Vulkan
  fixes (init idempotency, descriptor/sampler lifetime, dynamic
  viewport/scissor, render pass clear, format probing).

Both OAK_ENABLE_DYNAMIC_RENDER_BACKEND=ON and OFF configurations
build and pass ctest (4/4).
2026-07-13 10:19:29 +08:00
Mike-Solar 225f8505c2 feat(render): dynamic OpenGL/Vulkan backend split and backend-neutral viewer
- Extract libolive-rendercore static library to minimize backend link boundary.
- Add DynamicRenderer adapter with C ABI (oakgl/oakvulkan shared libs).
- Make OAK_ENABLE_DYNAMIC_RENDER_BACKEND default ON with OpenGL fallback.
- Implement VulkanRenderer prototype (textures, shaders, UBO blit, readback).
- Add backend-neutral viewer readback path (offscreen -> QImage -> QPainter).
- Refactor PluginRenderer to be renderer-agnostic; OFX plugins fall back to CPU
  path on non-OpenGL backends while preserving OpenGL render path.
- Add Renderer::AttachOutputTexture/DetachOutputTexture and C ABI forwards.
- Update docs/zh/render-backend-dynamic-plan.md for Phase 3/4/5.
2026-07-13 10:19:29 +08:00
Mike-Solar 5fc8232671 Add render backend capability info ABI 2026-07-13 10:19:29 +08:00
Mike-Solar 38c5afb13d Add Vulkan backend placeholder with dynamic fallback 2026-07-13 10:19:29 +08:00
Mike-Solar 3f43073261 Add dynamic backend load smoke test 2026-07-13 10:19:29 +08:00
Mike-Solar d5d70d0151 Add dynamic render backend adapter scaffold 2026-07-13 10:19:29 +08:00
Mike-Solar 341283b1cd Add graphics backend selection 2026-07-13 10:19:29 +08:00
Mike-Solar 8ae8e3a159 Implement proxy media workflow 2026-07-13 10:19:29 +08:00
Mike-Solar 0daad22129 Complete render process isolation phases 4 and 5 2026-06-06 23:31:52 +08:00
Mike-Solar 042f008a02 Add decoded input slots for render workers 2026-06-04 21:32:43 +08:00
Mike-Solar 98c884c381 Wire render worker pool into render manager 2026-06-04 16:23:36 +08:00
Mike-Solar b23e01b916 Add render worker IPC loop 2026-06-04 13:57:36 +08:00
Mike-Solar a2af4b5bf6 fix ci 2026-06-03 14:52:32 +08:00
Mike-Solar 9a4d635a7a Merge branch 'main' of https://github.com/OakVideoEditorCommunity/oak 2026-05-28 21:43:57 +08:00
Mike-Solar 9cae5d9c5f fix Ubuntu and Windows CI 2026-05-28 21:43:33 +08:00
孙羽 00f57533e6 Add null checks for color processing functions 2026-05-28 18:21:42 +08:00
Mike-Solar 0daef48b62 fix: remove <qtypes.h> to fix Linux CI. 2026-05-21 16:53:55 +08:00
Mike-Solar a0abf9cfb0 Fixed: fixed black screen when pulling playhead back. 2026-05-21 16:29:39 +08:00
Mike-Solar 2a84027ff9 fix(renderer): macOS TBDR cross-context sync and OFX instance thread-safety
This commit fixes crashes (SIGSEGV in CImg blur_bilateral) and black-frame
corruption artifacts during playback and scrubbing on macOS Apple Silicon.

Root cause analysis:
1. macOS uses Tile-Based Deferred Rendering (TBDR). glFlush() does not
   guarantee tile memory writeback, causing glReadPixels to read incomplete
   tiles (black/corrupted frames) and cache them to disk.
2. Olive uses multiple shared OpenGL contexts (RenderProcessor contexts vs.
   thread-local PluginRenderer context). glFinish() only waits for the
   current context, not the shared context that produced the texture. CPU
   readback in PluginRenderer could read partially-rendered tiles.
3. OlivePluginInstance and OliveClipInstance are not thread-safe. Concurrent
   RenderProcessors could corrupt internal QMap/images_ and params_ via
   setInputTexture/renderAction races.

Fixes:
- OpenGLRenderer::Flush() on macOS now uses glFinish() unconditionally.
- OpenGLRenderer::DownloadFromTexture() and OpenGLRenderer::Blit() insert
  glFinish() before readback/detach to ensure tile writeback completes.
- PluginRenderer::RenderPlugin() now acquires a per-instance mutex to
  serialize concurrent OFX render calls.
- Before CPU readback in PluginRenderer, flush the renderer that originally
  produced each input texture, ensuring cross-context synchronization.
- RenderProcessor::ProcessVideoFootage() flushes after BlitColorManaged.
- Add black-frame detection in ProcessVideoCacheJob() to auto-purge TBDR-
   corrupted cache files.
- Add diagnostic qDebug() logging in viewer, decoder, renderer, and plugin
  paths to aid future debugging.
2026-05-17 14:54:49 +08:00
Mike-Solar ff0eee3a88 perf(plugin): cache PluginRenderer per-thread and skip redundant clip prefs
Fix three performance traps in the OFX plugin preview pipeline that
  caused slideshow-like performance when any plugin was active.

  1. Eliminate per-frame PluginRenderer creation (GL FBO alloc/free)

     RenderProcessor is stack-allocated per ticket, so its
     plugin_renderer_ member was constructed and destroyed every frame.
     PluginRenderer inherits OpenGLRenderer, whose PostInit() calls
     glGenFramebuffers() and whose destructor calls glDeleteFramebuffers().
     On Apple Silicon's TBDR this is pathologically expensive.

     Fix: use a thread_local cached PluginRenderer so each render thread
     creates it only once and reuses it forever.

  2. Call getClipPreferences() conditionally

     The code unconditionally called instance->getClipPreferences() on
     every single frame. This dispatches kOfxImageEffectActionGetClipPreferences
     into the plugin even when no inputs or parameters have changed.

     Fix: check areClipPrefsDirty() first. The OpenFX Host Support library
     already tracks this flag and sets it to true when slave params or clip
     connections change.

  3. Call ApplyParamOverrides() before renderAction

     ApplyParamOverrides() was defined but never invoked, so animated
     plugin parameters were never pushed into the OFX instance before
     rendering.

     Fix: call it after beginRenderAction() and before renderAction(),
     injecting the current NodeValueRow values at the correct OfxTime.
2026-05-16 17:34:29 +08:00
Mike-Solar 3845c31b37 perf(plugin): eliminate GPU↔CPU ping-pong in OFX render path
This commit removes redundant readbacks and uploads in the OpenFX
  plugin pipeline, achieving zero-copy rendering for GL-capable
  plugins and reducing CPU path overhead.

  PluginRenderer (OpenGL path):
  - Skip ReadbackTextureToFrame + ConvertFrameIfNeeded + Upload after
    plugin render. The destination texture is already valid on GPU.
  - Pass readback_cpu=false to setInputTexture() so input textures are
    provided via loadTexture() (GL texture IDs) instead of being
    downloaded to CPU Image buffers.
  - Remove duplicate ReadbackTextureToFrame block between
    getClipPreferences and the second setInputTexture call.

  OliveClipInstance:
  - Add optional bool readback_cpu=true to setInputTexture(). When
    false, only params and input_textures_ are updated; CPU readback
    and memcpy into Image are skipped.
  - Add pruneImagesCache() to prevent unbounded growth of images_.
    Input clips are limited to 8 cached frames; output clips are
    left untouched.

  Micro-optimizations:
  - Replace per-row memcpy loops with single block memcpy when
    src/dst strides are contiguous (common case in Olive pipeline).
  - Remove dead GL_PREAMBLE macro definition.

  fix(viewer): resolve playback head lag, frozen frames, and pause delay

  Three playback pipeline behavioral issues are fixed:

  1. Prequeue blocked playhead start:
     Reduce kVideoPlaybackInterval from 0.5s to 0.1s. This lowers
     prequeue length from 15–30 frames to 3–6 frames, so the
     playback timer starts much sooner after pressing Play.

  2. Frozen display during playback:
     Relax the hard frame-drop logic in RendererGeneratedFrameForQueue.
     When the queue has fewer than 2 frames, keep late frames instead
     of dropping them, preventing the viewer from freezing entirely
     when rendering cannot keep up with playback speed.

  3. Delayed frame update after pause:
     Cancel in-flight render tickets in PauseInternal() before
     deleting queue watchers. Previously the render thread continued
     processing stale playback frames, blocking the single-frame
     render requested by UpdateTextureFromNode().
2026-05-16 16:45:13 +08:00
Mike-Solar 7ebfebb29a Fix OFX plugin render failures and stabilize integration tests
This commit resolves several categories of OFX plugin failures that
  manifested as magenta (pink) render output or crashes:

  1. Param default-value initialization
     - IntegerInstance, DoubleInstance, BooleanInstance, ChoiceInstance,
       and StringInstance now read kOfxParamPropDefault from the descriptor
       at construction time. Previously, when no PluginNode was attached
       (integration-test mode), get() returned 0/0.0/false, causing
       generator plugins to receive invalid extent/format/PAR values and
       crash in coordinate assertions.
     - IntegerInstance also fixed uninitialized `id` that caused
       kOfxStatErrBadHandle in CImg plugins.

  2. Clip property initialization
     - newClipInstance() now seeds pixelDepth and components from the
       host VideoParams instead of leaving them as None. This prevents
       Transform3x3Plugin and similar plugins from asserting on
       getPixelComponentCount() during fetchClip inside createInstance.
     - getAspectRatio() and getProjectPixelAspectRatio() now fall back
       to 1.0 when the project's PAR is not yet set, avoiding division-
       by-zero in coordinate conversion.

  3. Frame-rate and time-base preservation
     - setInputTexture() no longer overwrites the clip's frame_rate or
       time_base with the input texture's values. Multi-input plugins
       were crashing because setupClipPreferencesArgs throws when inputs
     have mismatched rates.

  4. Render loop hardening
     - getClipPreferences() is now wrapped in try/catch so that frame-
       rate mismatch exceptions mark render failure instead of aborting
       the render thread.
     - getRegionOfInterestAction() treats kOfxStatErrBadHandle as non-
       fatal and falls back to default RoI.
     - RenderPlugin syncs all clip instances after setVideoParam so that
       getAspectRatio/getFrameRate return valid values before
       createInstanceAction queries them.

  5. Test suite updates
     - All PluginMisc tests now use F32 input to match the host pipeline
       default.
     - CreateGradientTexture fixed to support F32 pixel format.
     - Added CImgBilateral and CImgGuided_MultiInput tests.
     - Secret parameters are now registered as hidden Node inputs so that
       getClipPreferences can read them (fixes generator pink screen).

  6. Debug logging in HostSupport
     - clipGetImage and clipGetRegionOfDefinition now catch exceptions
       and log the failing clip name for easier debugging.
2026-05-15 21:32:28 +08:00
Mike-Solar 43ba1c4642 fix ofx plugin bug 2026-05-14 20:26:17 +08:00
Mike-Solar 599c876d03 全链路强制F32 2026-05-14 01:51:14 +08:00