fix: SG-43367: eliminate EXR+WAV playback stuttering - #1350
Draft
bernie-laberge wants to merge 2 commits into
Draft
fix: SG-43367: eliminate EXR+WAV playback stuttering#1350bernie-laberge wants to merge 2 commits into
bernie-laberge wants to merge 2 commits into
Conversation
… OpenEXR)
Fixes stuttering during playback of high-resolution multi-part EXR sequences
with WAV/MOV audio on Linux. The image was correct but playback dropped well
below the target frame rate even with frames fully resident in cache. Root
causes were in the GPU texture-upload path, the EXR decode scheduling, and an
OpenEXR 3.3 I/O regression. Playback now holds 24 fps with ~100% of large
frames on the DMA fast path and per-frame present stalls effectively gone.
GPU texture upload (primary fix) -- src/lib/ip/IPCore/ImageRenderer.{cpp,h}:
- Make the staging PBO transient. It was allocated in initializeTexture() and
pinned to the cached TextureDescription for the texture's entire cache life
(~10+ frames), so with a large look-ahead cache the small fixed PBO pool was
permanently occupied and most large frames fell back to the slow synchronous
glTexImage2D-from-client-memory path (~72 ms, ~1.4 GB/s). The PBO is now
acquired inside uploadPlane() for a single upload and released back to the
pool immediately after the transfer is issued, so a handful of buffers serve
an unbounded stream. Result: PBO fast-path use went ~64% -> 99.9% and CPU
submit ~72 ms -> ~14 ms (~6.8 GB/s) for 4546x2864 frames.
- Upload 3-channel RGB half/float frames via a native RGBA path: allocate the
texture as GL_RGBA16F/RGBA32F and expand RGB->RGBA on the CPU during upload
(GL_TEXTURE_RECTANGLE only). GL_RGB16F/RGB32F have no native DMA path; the
driver was expanding per-pixel on upload, which is far slower.
- Fix a texture cross-reuse corruption: an expanded 3ch->RGBA texture and a
genuine 4ch RGBA texture produce identical destination geometry/format, so
the getTexture() Compatible-reuse path could recycle one for the other and
run the wrong upload path (wrong channel stride), causing image artifacts.
compatible() now also compares expandRGBToRGBA so the two are never reused
across each other.
RGB->RGBA expanders -- src/lib/image/TwkFB/FastMemcpy.{cpp,h}:
- Add parallel (task-pool) expand_rgb_to_rgba_16bit/32bit(_MP) helpers used by
the upload path.
EXR decode scheduling -- src/lib/ip/IPBaseNodes/FileSourceIPNode.cpp,
src/lib/ip/IPCore/IPGraph.{cpp,h}, src/lib/ip/IPCore/IPCore/IPNode.h:
- When a source mixes slow-random-access media (e.g. a MOV used only for audio)
with fast EXR image media, no longer serialize the whole source onto a single
caching thread. testEvaluate() now inspects only the media component actually
supplying the displayed image and reports hasFastVideoSource, and the caching
scheduler only forces single-threaded slow-media handling when the frame has
no fast image source to parallelize. This restores concurrent EXR decoding
for the common "EXR + MOV-for-audio" layout.
OpenEXR 3.3 I/O regression -- src/lib/image/IOexr/FileStreamIStream.{cpp,h},
src/lib/image/IOexr/IOMultiPartEXR.cpp:
- OpenEXR 3.3.x is much slower for custom Imf::IStream subclasses that do not
implement size()/stateless read(). RV's default memory-mapped I/O uses such
a stream. Implement size(), isStatelessRead() and the stateless read()
overload (guarded by IOEXR_HAS_STATELESS_ISTREAM) so 3.3+ takes the fast,
concurrent read path from RV's mapped buffers.
Playback diagnostics (opt-in, env-gated) -- src/lib/base/TwkUtil/
PlaybackDiagnostics.{cpp,h} (+ CMakeLists), and instrumentation in
Session.{cpp,h}, Application.cpp, GLView.cpp, FBCache.{cpp,h},
IPGraph.cpp, FileSourceIPNode.cpp, ImageRenderer.cpp,
ALSASafeAudioModule/ALSASafeAudioRenderer.cpp (+ CMakeLists):
- Add a thread-safe, RV_PLAYBACK_DIAG-gated CSV logger capturing background
decode times/concurrency/compression, audio cache-miss/underrun events,
buffering pauses and frame skips, display pacing (interval/dframe/refreshes),
cache hit/miss and runway, per-plane GPU upload cost/PBO usage, and a stall
anatomy split (present/composite/swap vs in-graph work). All timing is behind
the env gate and has no cost when disabled.
- tools/analyze_playback_diag.py: analyzer that summarizes the log and reports
a bottleneck verdict (decode vs audio vs cache vs present).
Co-authored-by: Cursor <cursoragent@cursor.com>
When the OpenEXR "Automatic Threads" preference is on (exrcpus == 0), RV set the shared OpenEXR global thread pool to numCPUs-1 (e.g. 63 on a 64-core box). Because every EXR decode draws from that single global pool, on high-core machines the decode threads starve RV's playback/UI, audio and caching threads and cause dropped frames -- worst with DWA/DWAB-compressed EXRs. Add Rv::automaticExrThreadCount() and use it wherever the Automatic value is applied: - threads = (logicalCores > 16) ? logicalCores/2 : (logicalCores > 1 ? logicalCores-1 : 1) - On hyper-threaded systems logicalCores/2 is roughly the physical core count, leaving headroom for the main/UI, audio and caching threads. - Overridable at runtime via the RV_EXR_AUTO_MAX_THREADS environment variable. - Behavior on <=16-core machines is unchanged. Call sites updated: src/bin/apps/rv/main.cpp, src/bin/nsapps/RV/main.cpp, and RvPreferences::exrNumThreadsFinished()/exrAutoThreads(). Manual thread counts (exrcpus > 0) and rvio (batch, no interactive UI to starve) are unchanged. Docs: document the Automatic heuristic and RV_EXR_AUTO_MAX_THREADS in the RV user manual (EXR decoding threads section) and refresh the -exrcpus entries in the RV and RVIO command-line reference tables. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
DO NOT REVIEW : Waiting for customer confirmation that this fix solves their issue first
fix: SG-43367: eliminate EXR+WAV playback stuttering
Linked issues
NA
Summarize your change.
Fixes stuttering during playback of high-resolution multi-part EXR sequences with WAV/MOV audio on Linux. The image was correct but playback dropped well below the target frame rate even with frames fully resident in cache. Root causes were in the GPU texture-upload path, the EXR decode scheduling, and an OpenEXR 3.3 I/O regression. Playback now holds 24 fps with ~100% of large frames on the DMA fast path and per-frame present stalls effectively gone.
GPU texture upload (primary fix) -- src/lib/ip/IPCore/ImageRenderer.{cpp,h}:
RGB->RGBA expanders -- src/lib/image/TwkFB/FastMemcpy.{cpp,h}:
EXR decode scheduling -- src/lib/ip/IPBaseNodes/FileSourceIPNode.cpp, src/lib/ip/IPCore/IPGraph.{cpp,h}, src/lib/ip/IPCore/IPCore/IPNode.h:
OpenEXR 3.3 I/O regression -- src/lib/image/IOexr/FileStreamIStream.{cpp,h}, src/lib/image/IOexr/IOMultiPartEXR.cpp:
Playback diagnostics (opt-in, env-gated) -- src/lib/base/TwkUtil/ PlaybackDiagnostics.{cpp,h} (+ CMakeLists), and instrumentation in Session.{cpp,h}, Application.cpp, GLView.cpp, FBCache.{cpp,h}, IPGraph.cpp, FileSourceIPNode.cpp, ImageRenderer.cpp, ALSASafeAudioModule/ALSASafeAudioRenderer.cpp (+ CMakeLists):
Describe the reason for the change.
Playback of high-resolution multi-part EXR sequences with WAV/MOV audio on Linux could potentially stutter
Describe what you have tested and on which operating system.
Successfully tested on Rocky Linux 9
Add a list of changes, and note any that might need special attention during the review.
If possible, provide screenshots.