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.
Run lupdate to pull the latest source strings (including new proxy
settings/menu text) into all .ts files. Translations for the new strings
are marked unfinished and can be filled in by translators.
- Extend ProxyManager::ProxyParams with crf and preset, and update
ProxyTask/ProxyParamsEqual to use them.
- Add global config keys ProxyWidth, ProxyHeight, ProxyCRF, ProxyPreset.
- Add a Proxy Settings group to Preferences -> Disk with width/height/CRF/preset
controls.
- Read proxy settings from config when generating proxies from the timeline.
- Add Tools -> Proxy Settings... menu entry that opens Preferences on the Disk tab.
- Add ConfigDialogBase::SetCurrentTab() so PreferencesDialog can start on a
specific tab.
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.
ffmpeg could not infer the container format because ProxyManager writes
proxies to a temporary '.mp4.working' file. Explicitly pass '-f mp4' (or
the configured proxy extension) so ffmpeg knows the output format
regardless of the temporary extension.
- 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.
- Introduce ReadDirectionInput() helper that accepts both integer and
string ('Forward'/'Inverse') representations of the direction combo.
- Log every processor creation with the raw direction value and the OCIO
transform direction being used, along with whether it is main or worker.
- This helps determine why Forward/Inverse switching reportedly has no
effect in the viewer/worker.
Tests still pass.
EnsureProcessor() was returning early whenever a processor existed and
processor_dirty_ was false, without checking whether the file or direction
input had changed. As a result, switching Forward/Inverse in the main GUI
re-used the old processor and produced no visible difference.
Now EnsureProcessor() also compares the current inputs against the values
used to create last_processor_, so direction/file changes always trigger a
regeneration before the color transform job is emitted.
- 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.
Temporarily disable the last_path_/last_direction_ reuse check to rule
out stale processor reuse as the cause of LUT changes not appearing in
the viewer.
Reversing the order ensures that any render tasks that finish after the
cancel request will find the cache already invalidated, preventing stale
LUT-processed frames from being written back and shown in the viewer.
Checking applicationName was not reliable. The worker process uses
QGuiApplication while the main process uses QApplication, so use
qobject_cast<QApplication*> to determine whether it is safe to access
RenderManager/PreviewAutoCacher. This prevents the worker from crashing
when loading or switching LUT files.
The LUT processor generation was calling RenderManager::GetCacher()
during project load in the render worker, but the worker has no
RenderManager/PreviewAutoCacher. This caused a SEGV and made the main
process hang waiting for the worker. Only cancel/invalidate caches in
the main GUI process.
After synchronously generating the new LUT processor, cancel any
running background video cache jobs before invalidating the cache.
This prevents the preview autocacher from re-rendering the entire
timeline, which was causing the UI to freeze, while still updating
the current visible frame with the new LUT.
Background generation caused the UI to freeze indefinitely when
switching LUT files, likely due to a deadlock between the worker
process, the preview autocacher, and the asynchronous set_processor
path. Synchronous generation is fast enough for typical 33^3 .cube
files and keeps the cache invalidation logic simple and safe.
The passthrough fix in OCIOBaseNode::Value() is retained so the
viewer shows the input frame while a processor is being created.
InvalidateAll() on the OCIO LUT node caused the preview autocacher to
re-render the entire timeline, freezing the UI when switching LUT files.
Instead, let the new processor be used naturally on the next render
request (scrubbing/playback).
InvalidateAll() on the OCIO LUT node triggered the worker's
PreviewAutoCacher to re-cache the entire timeline, causing the main
process to freeze while waiting for frames. Only invalidate in the
main GUI process so the viewer refreshes; the worker will naturally
use the new processor on its next render request.
- Pass through input texture when the LUT processor is not ready yet,
preventing black frames while the processor is being generated.
- Serialize processor generation with a single in-flight task to avoid
concurrent OCIO lock contention that could freeze the UI.
- Invalidate cached frames after the async processor is set so the viewer
refreshes automatically without requiring the playhead to be moved.
- Add OAK_DISABLE_HWACCEL environment variable to force software decoding.
- Add FFmpegDecoderHW regression test for H.264 4:2:2 10-bit decoding.
- Document that Vulkan now passes an end-to-end upload/blit/download test
on real hardware.
- List recently landed fixes: shared vertex/fragment UBO, descriptor set
layout, render pass dependencies, image layout transitions, framebuffer
and sampler caching, grayscale swizzle, texture-enable uniforms.
- Add remaining gaps: iterative/pin-pong multi-pass Blit, 1/3-channel
upload/download alignment, and full viewer/proxy/export smoke tests.
- 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.
- 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).
- 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.
- dynamic plan: mark that RenderManager::backend() now syncs with
DynamicRenderer's actual loaded backend after internal fallback.
- manual test plan: add checks in 10.2/10.3 that RenderManager reports
the actual runtime backend (OpenGL after Vulkan fallback).
No code changes; ctest passes 4/4.
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.
- 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).
- 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.