- 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.
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.
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.
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().
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.
This commit extends the OFX plugin support in Olive by:
- Initializing and scanning for OFX plugins
- Updating PluginNode to handle OFX plugin parameters and inputs
- Adding necessary methods and properties for OFX plugin integration
- Enhancing NodeFactory to include OFX plugin nodes
- Refactoring and renaming OliveInstance to OlivePluginInstance
- Introducing new classes for parameter handling (ParamInstance)
- Adding PluginJob for rendering OFX plugins
- Adjusting CMakeLists.txt files to include new source files