Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/frame_colorcorrect.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ class FrameColorCorrect {
void deinit();
bool ready() const { return ready_; }

// Update the correction parameters of an already-initialised context.
// The uniforms are uploaded per frame in process(), so this takes effect
// on the next frame. Must be called from the processor thread.
void set_params(float gain, float offset) { gain_ = gain; offset_ = offset; }

// Register the current OSD DMA-buf for compositing. Called whenever the
// OSD double-buffer switches. The EGLImage is cached and only re-imported
// when prime_fd changes. Must be called from the processor thread.
Expand Down
31 changes: 21 additions & 10 deletions src/frame_processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,14 @@ void FrameProcessor::set_osd_blend(int prime_fd, uint32_t w, uint32_t h, uint32_
osd_info_.stride_px = stride_px;
}

void FrameProcessor::set_color_correction(float gain, float offset, int drm_fd) {
cc_gain_ = gain;
cc_offset_ = offset;
if (drm_fd >= 0) drm_fd_ = drm_fd; // update if caller supplies one
color_correct_.store(true, std::memory_order_relaxed);
// Actual EGL/GL init happens lazily on the processor thread (first frame)
void FrameProcessor::set_color_correction(float gain, float offset) {
cc_gain_.store(gain, std::memory_order_relaxed);
cc_offset_.store(offset, std::memory_order_relaxed);
// Release-store so the processor thread can't observe the enable before
// the gain/offset it belongs to.
color_correct_.store(true, std::memory_order_release);
// Actual EGL/GL init happens lazily on the processor thread (first frame);
Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.
// an already-initialised context picks the new params up on the next frame.
}

// ── Processor thread entry point ────────────────────────────────────────────
Expand Down Expand Up @@ -174,9 +176,16 @@ void FrameProcessor::process_loop() {
// The GL render target is at OUTPUT size (dst_w × dst_h);
// samplerExternalOES handles any input-to-output resize implicitly.
// Re-init when output dimensions change.
bool need_gl = drm_fd_ >= 0 &&
(color_correct_.load(std::memory_order_relaxed) ||
osd_snap.prime_fd >= 0);
// The GL context is created once and outlives any number of
// recordings, so the correction parameters must be re-read from
// the (UI-writable) members every frame -- baking them in at
// init() would freeze whatever colortrans state happened to be
// active when the first DVR started.
bool cc_on = color_correct_.load(std::memory_order_acquire);
float cc_gain = cc_on ? cc_gain_.load(std::memory_order_relaxed) : 1.f;
float cc_offset = cc_on ? cc_offset_.load(std::memory_order_relaxed) : 0.f;

bool need_gl = drm_fd_ >= 0 && (cc_on || osd_snap.prime_fd >= 0);
if (gl_init_done_ && (dst_w != gl_out_w_ || dst_h != gl_out_h_)) {
color_gl_.deinit();
gl_init_done_ = false;
Expand All @@ -185,7 +194,7 @@ void FrameProcessor::process_loop() {
gl_init_done_ = true;
gl_out_w_ = dst_w;
gl_out_h_ = dst_h;
color_gl_.init(drm_fd_, dst_w, dst_h, cc_gain_, cc_offset_);
color_gl_.init(drm_fd_, dst_w, dst_h, cc_gain, cc_offset);
}

bool ok;
Expand All @@ -194,6 +203,8 @@ void FrameProcessor::process_loop() {
// → NV12 (RGA CSC, no resize — GBM BO is at output size)
ok = color_gl_.ready();
if (ok) {
color_gl_.set_params(cc_gain, cc_offset);

if (osd_snap.prime_fd >= 0)
color_gl_.set_osd(osd_snap.prime_fd,
osd_snap.width, osd_snap.height,
Expand Down
17 changes: 11 additions & 6 deletions src/frame_processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,9 @@ class FrameProcessor {
void set_resolution(EncResolution r) { target_res_.store((int)r, std::memory_order_relaxed); }

// Enable GPU color correction using the DRM gamma formula y = clamp((x+offset)*gain, 0, 1).
// Safe to call from any thread. drm_fd is used to create the GBM/EGL context (lazy).
void set_color_correction(float gain, float offset, int drm_fd);
// Safe to call from any thread. The GBM/EGL context is created lazily on
// the processor thread from the DRM fd given at construction.
void set_color_correction(float gain, float offset);

// Enable/disable color correction at runtime without changing the stored params.
// Thread-safe: safe to toggle from the UI thread while the pacer is running.
Expand Down Expand Up @@ -128,10 +129,14 @@ class FrameProcessor {
// Written by UI thread (set_color_correction / set_color_correction_enabled),
// read by processor thread — must be atomic where shared.
std::atomic<bool> color_correct_{false};
bool gl_init_done_{false};
uint32_t gl_out_w_{0}, gl_out_h_{0}; // output dims at last GL init
float cc_gain_{1.f}, cc_offset_{0.f};
int drm_fd_{-1}; // DRM fd for GBM/EGL (passed at construction)
bool gl_init_done_{false}; // processor thread only
uint32_t gl_out_w_{0}, gl_out_h_{0}; // processor thread only: dims at last GL init
std::atomic<float> cc_gain_{1.f};
std::atomic<float> cc_offset_{0.f};
// DRM fd for GBM/EGL. Immutable after construction: the processor thread
// reads it on every frame, so a runtime write from the UI thread would be
// a data race. const enforces that rather than leaving it to convention.
const int drm_fd_;
FrameColorCorrect color_gl_;
};

Expand Down
6 changes: 3 additions & 3 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ extern "C" {
void dvr_reenc_notify_colortrans(int enabled) {
if (!frame_proc) return;
if (enabled)
frame_proc->set_color_correction(live_colortrans_gain, live_colortrans_offset, drm_fd);
frame_proc->set_color_correction(live_colortrans_gain, live_colortrans_offset);
else
frame_proc->set_color_correction_enabled(false);
}
Expand Down Expand Up @@ -830,7 +830,7 @@ extern "C" {
dvr_reenc_on_fatal_error);
if (enable_live_colortrans)
frame_proc->set_color_correction(live_colortrans_gain,
live_colortrans_offset, drm_fd);
live_colortrans_offset);
pthread_create(&g_tid_fproc, NULL, &FrameProcessor::__THREAD__, frame_proc);
dvr_configure_reenc_receiver();
if (receiver) receiver->set_dvr_reenc_on_start(dvr_reenc_on_start);
Expand Down Expand Up @@ -1878,7 +1878,7 @@ int main(int argc, char **argv)
dvr_reenc_on_fatal_error);
if (enable_live_colortrans) {
frame_proc->set_color_correction(live_colortrans_gain,
live_colortrans_offset, drm_fd);
live_colortrans_offset);
spdlog::info("Encoder color correction enabled: gain={} offset={}",
live_colortrans_gain, live_colortrans_offset);
}
Expand Down