Commit Graph
30 Commits
Author SHA1 Message Date
Mike-Solar bff06e00e5 refactor: split Core into EngineCore (engine) and Core (UI)
EngineCore (new app/coreengine.{h,cpp}) owns every engine-safe part of
the old Core singleton: CoreParams, lifecycle of the engine managers,
UndoStack, tool/snapping/timecode state, locale, autorecovery, recent
projects, footage filters, clipboard, project registry, type
declarations, and the proxy toggle. UI dependencies are inverted
through hooks instead: status-bar/cache-full signals and std::function
handlers for image-sequence confirmation, footage relink, OTIO import,
project save/close and layout load (same pattern as
Config::ErrorHandler).

Core (app/) now derives from EngineCore and keeps only UI behavior:
the main window, dialogs, panel heuristics, import/export flows and
project lifecycle presentation. Its public API is unchanged (all
inherited), and Core::instance() covariantly static_casts the engine
singleton. The render worker constructs EngineCore directly, making it
the first binary that no longer needs the UI side of Core.

~25 engine call sites move from core.h to coreengine.h; a dozen more
drop a vestigial core.h include (gaining direct includes for symbols
they were borrowing transitively). Full gtest suite green (1986 tests,
0 failures).
2026-07-20 01:38:42 +08:00
Mike-Solar bb40b4923e style: unify identifier naming per updated conventions
Automated with clang-tidy readability-identifier-naming (config added to
.clang-tidy) plus scripted passes, per the updated rules now documented
in CONTRIBUTING.md:

- types (class/struct/enum/alias/template params): PascalCase
- functions, variables, members: snake_case (incl. rational -> Rational)
- private/protected members: trailing underscore; static member
  variables likewise (instance_, available_themes_)
- constants and enum values: snake_case (kLinear -> k_linear,
  F32P -> f32p); ALL_CAPS reserved for macros
- macros: OAK_ prefix (OLIVE_ADD_TEST/OLIVE_ASSERT/OLIVE_CONFIG ->
  OAK_ADD_TEST/OAK_ASSERT/OAK_CONFIG, GL_PREAMBLE -> OAK_GL_PREAMBLE,
  include guards -> OAK_*)
- file names: all lowercase (Current/Plugin/OliveHost/OliveClip/
  OlivePluginInstance -> current/plugin/olivehost/oliveclip/
  oliveplugininstance)
- getters share the member name sans underscore, setters set_foo()
- Qt and third-party (OpenFX) virtual overrides and framework callbacks
  keep their original names (exempt in .clang-tidy)

Manual follow-ups required where automation could not reach:
- string-based QMetaObject/SIGNAL/SLOT references updated to renamed
  methods (AddTask, CreatedFile, DeleteSpecificFile, moveSelectionUp, ...)
- macro bodies referencing renamed methods (OLIVE_CONFIG,
  NODE_DEFAULT_DESTRUCTOR, MANAGEDDISPLAYWIDGET_*)
- self-shadowing locals renamed where signals/methods became same-named
  (size_changed, worker_count, selected_items, import param, filters)
- third_party OFX member/namespace usages restored (OFX::Host::*,
  _created, _clipPrefsDirty, createInstance, clearPersistentMessage)
- STL protocol aliases restored (const_iterator) with .clang-tidy
  ignore rules; qHash overloads restored

Full build and test suite pass: ctest 4/4, ~1960 gtest cases green.
2026-07-19 16:10:54 +08:00
Mike-Solar 3a3ead6fc0 app: route all FFmpeg access through the ffmpeg_bridge C API
Replace every direct FFmpeg call in the editor and the render worker
with the pure C ffmpeg_bridge API, wrapped in thin C++ adapters that
preserve the original interfaces:

- avframeptr.h: olive::AVFrame adapter around FBFrame handles
- ffmpegutils: format conversion helpers on FB_* constants; the int
  overload is renamed GetCompatibleBridgePixelFormat to avoid a silent
  overload-resolution trap with the PixelFormat enum
- ffmpegdecoder/ffmpegencoder: rewritten as handle-based adapters over
  FBDecoder/FBProbe/FBEncoder/FBScaler/FBResampler
- audioprocessor: FBAudioGraph push/pull adapter
- pluginrenderer/OliveClip: sws/pixdesc usage converted to FBScaler and
  fb_pix_fmt_* queries
- AudioParams/channel layouts are plain uint64_t masks everywhere

Build integration: the root project no longer links FFMPEG directly;
only ffmpeg_bridge does. Binaries resolve the bridge library at runtime
via @loader_path inside the macOS app bundle (copied there post-build)
and via $ORIGIN/../ffmpeg_bridge/bin on Linux; on Windows the DLL is
installed next to the executables, so packages on all three platforms
ship the bridge library.

ffmpeg_bridge gains the extra API the adapters need:
fb_frame_make_writable, fb_decoder_get_format_duration,
fb_resampler_convert_frame, FB_PIX_FMT_YUV440P, SRT validation in
fb_probe_read_subtitle_stream, packed/planar fixes in
fb_encoder_write_audio, and a component-size fix in
fb_pix_fmt_component_size.
2026-07-15 23:00:06 +08:00
Mike-Solar e5eeaddf2f format: reformatting files 2026-07-13 15:30:43 +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 a2af4b5bf6 fix ci 2026-06-03 14:52:32 +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
Mike-Solar f3c50017e9 rendering still not correct 2026-04-19 18:59:56 +08:00
Mike-Solar 3b5b0187cb fix chroma keyer 2026-04-12 01:42:27 +08:00
Mike-Solar c1bcfeb78b finish plugin suppoirt 2026-01-17 16:49:21 +08:00
Mike-Solar a2698e7ef4 solve problem invalid roi and param 2026-01-17 16:41:03 +08:00
Mike-Solar e851653fa3 尝试修复粉紫屏未果 2026-01-16 21:11:24 +08:00
Mike-Solar 4d393f3d23 尝试解决插件bug 2026-01-10 18:56:58 +08:00
Mike-Solar e37972b227 Try to fix plugin issue 2026-01-05 21:31:35 +08:00
Mike-Solar 8ed5660faf solve some bugs 2026-01-05 18:01:13 +08:00
Mike-Solar b8669f6a11 Change project name; 2026-01-05 16:22:26 +08:00
Mike-Solar cad331eb2c Fix compile errors 2026-01-05 01:50:05 +08:00
Mike-Solar c136cdf7f6 完成1 2026-01-05 00:03:51 +08:00
Mike-Solar 4cbdfd1a88 Finish TODO 8,9 2026-01-04 23:53:12 +08:00
Mike-Solar 3b16824f34 Ensure render path sets per-frame output data and handles ROD/bounds correctly. 2026-01-04 22:40:05 +08:00
Mike-Solar f191486375 Implement multi-input OFX clip wiring and texture handling
Store PluginJob input values for lookup
Add per-clip texture inputs on plugin nodes
Map input clips to textures during render (with Source fallback)
2026-01-04 22:30:41 +08:00
Mike Solar 7c0f37b0a7 Implement default methods for plugin parameter editing and progress, and integrate plugin rendering into the build system. 2025-12-24 21:07:17 +08:00
Mike-Solar 8a7b6cf869 Add OFX plugin support and related infrastructure
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
2025-11-09 17:03:56 +08:00