From 1e224edceb2977286ab49f17f1d15707924ee731 Mon Sep 17 00:00:00 2001 From: oiupoyt Date: Sat, 12 Sep 2026 11:25:14 +0530 Subject: [PATCH] encoder: fix color space to bt709, improve text sharpness, eliminate mmap thrashing, and enhance notification bar vibrancy --- src/bin/scythe-daemon.rs | 11 ++++--- src/encoder.rs | 40 ++++++++++++++++++++++--- src/overlay.rs | 34 ++++++++++++++++----- src/overlay_egui.rs | 64 +++++++++++++++++++++++++++++++++------- 4 files changed, 122 insertions(+), 27 deletions(-) diff --git a/src/bin/scythe-daemon.rs b/src/bin/scythe-daemon.rs index 7f4e540..e238bca 100644 --- a/src/bin/scythe-daemon.rs +++ b/src/bin/scythe-daemon.rs @@ -690,13 +690,12 @@ async fn main() -> Result<(), Box> { recv(ticker) -> _ => { while ticker.try_recv().is_ok() {} - if last_malloc_trim.elapsed().as_secs() >= 5 { - last_malloc_trim = std::time::Instant::now(); - #[cfg(target_os = "linux")] - unsafe { libc::malloc_trim(0); } - } - if !normal_recording && !config.replay_enabled { + if last_malloc_trim.elapsed().as_secs() >= 5 { + last_malloc_trim = std::time::Instant::now(); + #[cfg(target_os = "linux")] + unsafe { libc::malloc_trim(0); } + } has_new_frame = false; continue; } diff --git a/src/encoder.rs b/src/encoder.rs index 1bff95c..78172a9 100644 --- a/src/encoder.rs +++ b/src/encoder.rs @@ -75,6 +75,12 @@ impl VaapiEncoder { }; (*codec_ctx).flags |= AV_CODEC_FLAG_GLOBAL_HEADER as libc::c_int; + // Rec.709 Color Space & MPEG Limited Range (Broadcast / Web standard, avoids yellow tint) + (*codec_ctx).colorspace = AVColorSpace::AVCOL_SPC_BT709; + (*codec_ctx).color_primaries = AVColorPrimaries::AVCOL_PRI_BT709; + (*codec_ctx).color_trc = AVColorTransferCharacteristic::AVCOL_TRC_BT709; + (*codec_ctx).color_range = AVColorRange::AVCOL_RANGE_MPEG; + let mut hw_device_ctx: *mut AVBufferRef = ptr::null_mut(); let ret = av_hwdevice_ctx_create( &mut hw_device_ctx, @@ -123,10 +129,18 @@ impl VaapiEncoder { (*staged_nv12).format = AVPixelFormat::AV_PIX_FMT_NV12 as i32; (*staged_nv12).width = width as i32; (*staged_nv12).height = height as i32; + (*staged_nv12).colorspace = AVColorSpace::AVCOL_SPC_BT709; + (*staged_nv12).color_primaries = AVColorPrimaries::AVCOL_PRI_BT709; + (*staged_nv12).color_trc = AVColorTransferCharacteristic::AVCOL_TRC_BT709; + (*staged_nv12).color_range = AVColorRange::AVCOL_RANGE_MPEG; av_frame_get_buffer(staged_nv12, 32); let hw_frame = av_frame_alloc(); (*hw_frame).format = AVPixelFormat::AV_PIX_FMT_VAAPI as i32; + (*hw_frame).colorspace = AVColorSpace::AVCOL_SPC_BT709; + (*hw_frame).color_primaries = AVColorPrimaries::AVCOL_PRI_BT709; + (*hw_frame).color_trc = AVColorTransferCharacteristic::AVCOL_TRC_BT709; + (*hw_frame).color_range = AVColorRange::AVCOL_RANGE_MPEG; let sws_ctx = sws_getContext( width as i32, @@ -135,12 +149,28 @@ impl VaapiEncoder { width as i32, height as i32, AVPixelFormat::AV_PIX_FMT_NV12, - 1, + (SwsFlags::SWS_BICUBIC as libc::c_int) | (SwsFlags::SWS_ACCURATE_RND as libc::c_int), ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), ); + if !sws_ctx.is_null() { + let coeffs = sws_getCoefficients(SWS_CS_ITU709); + if !coeffs.is_null() { + sws_setColorspaceDetails( + sws_ctx, + coeffs, + 1, // srcRange: 1 (sRGB full range 0-255) + coeffs, + 0, // dstRange: 0 (MPEG limited range 16-235) + 0, + 1 << 16, + 1 << 16, + ); + } + } + Ok(Self { codec_ctx, hw_device_ctx, @@ -291,9 +321,11 @@ impl VaapiEncoder { 0, ); if p != libc::MAP_FAILED { - if self.dma_mmap_cache.len() >= 4 { - for (_, (old_p, old_size)) in self.dma_mmap_cache.drain() { - libc::munmap(old_p, old_size); + if self.dma_mmap_cache.len() >= 16 { + if let Some(old_fd) = self.dma_mmap_cache.keys().next().copied() { + if let Some((old_p, old_size)) = self.dma_mmap_cache.remove(&old_fd) { + libc::munmap(old_p, old_size); + } } } self.dma_mmap_cache.insert(*fd, (p, mmap_size)); diff --git a/src/overlay.rs b/src/overlay.rs index 34449b1..dac7dd5 100644 --- a/src/overlay.rs +++ b/src/overlay.rs @@ -354,22 +354,42 @@ pub fn show_shadowplay_toast(title: &str, subtitle: &str, icon: ToastIcon) { cr.rectangle(0.5, 0.5, w - 1.0, h - 1.0); let _ = cr.stroke(); - // 5. Animated countdown timer line on bottom edge (high visibility) + // 5. Animated countdown timer line on bottom edge (vibrant accent glow) let progress = 1.0 - (elapsed / total_dur).clamp(0.0, 1.0); let bar_h = 3.5; - cr.set_source_rgba(1.0, 1.0, 1.0, 0.15 * alpha); + let bar_w = (w * progress).max(0.0); + + // Track: glowing tinted accent baseline + cr.set_source_rgba(active_accent.0, active_accent.1, active_accent.2, 0.22 * alpha); cr.rectangle(0.0, h - bar_h, w, bar_h); let _ = cr.fill(); - let bar_w = (w * progress).max(0.0); - cr.set_source_rgba(active_accent.0, active_accent.1, active_accent.2, 0.95 * alpha); + // Ambient vibrant glow above bar + let glow_h = 3.0; + cr.set_source_rgba(active_accent.0, active_accent.1, active_accent.2, 0.28 * alpha); + cr.rectangle(0.0, h - bar_h - glow_h, bar_w, glow_h); + let _ = cr.fill(); + + // Solid vibrant core bar + cr.set_source_rgba(active_accent.0, active_accent.1, active_accent.2, 1.0 * alpha); cr.rectangle(0.0, h - bar_h, bar_w, bar_h); let _ = cr.fill(); + // Top neon specular edge highlight + let high_r = (active_accent.0 + 0.35).min(1.0); + let high_g = (active_accent.1 + 0.35).min(1.0); + let high_b = (active_accent.2 + 0.35).min(1.0); + cr.set_source_rgba(high_r, high_g, high_b, 0.90 * alpha); + cr.set_line_width(1.0); + cr.move_to(0.0, h - bar_h); + cr.line_to(bar_w, h - bar_h); + let _ = cr.stroke(); + + // Laser-sharp white leading tip indicator if bar_w > 2.0 { - cr.set_source_rgba(1.0, 1.0, 1.0, 0.85 * alpha); - cr.set_line_width(1.5); - cr.move_to(bar_w, h - bar_h); + cr.set_source_rgba(1.0, 1.0, 1.0, 1.0 * alpha); + cr.set_line_width(2.0); + cr.move_to(bar_w, h - bar_h - 1.0); cr.line_to(bar_w, h); let _ = cr.stroke(); } diff --git a/src/overlay_egui.rs b/src/overlay_egui.rs index 73e8e83..44c5f50 100644 --- a/src/overlay_egui.rs +++ b/src/overlay_egui.rs @@ -2224,18 +2224,40 @@ impl ScytheOverlayApp { egui::StrokeKind::Inside, ); - // 5. Animated Countdown Timer Line (bottom edge - high visibility) + // 5. Animated Countdown Timer Line (bottom edge - vibrant accent glow) let progress = 1.0 - (elapsed / total_dur).clamp(0.0, 1.0); let bar_h = 3.5_f32; - let bar_track = egui::Rect::from_min_size(egui::pos2(toast_rect.left(), toast_rect.bottom() - bar_h), egui::vec2(card_w, bar_h)); - painter.rect_filled(bar_track, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(255, 255, 255, (30.0 * anim_alpha) as u8)); let bar_w = (card_w * progress).max(0.0); + + // Track: glowing tinted accent baseline + let bar_track = egui::Rect::from_min_size(egui::pos2(toast_rect.left(), toast_rect.bottom() - bar_h), egui::vec2(card_w, bar_h)); + painter.rect_filled(bar_track, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(active_color.r(), active_color.g(), active_color.b(), (45.0 * anim_alpha) as u8)); + + // Ambient vibrant glow above bar + let glow_h = 3.0_f32; + let glow_rect = egui::Rect::from_min_size(egui::pos2(toast_rect.left(), toast_rect.bottom() - bar_h - glow_h), egui::vec2(bar_w, glow_h)); + painter.rect_filled(glow_rect, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(active_color.r(), active_color.g(), active_color.b(), (50.0 * anim_alpha) as u8)); + + // Solid vibrant core bar let bar_rect = egui::Rect::from_min_size(egui::pos2(toast_rect.left(), toast_rect.bottom() - bar_h), egui::vec2(bar_w, bar_h)); painter.rect_filled(bar_rect, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(active_color.r(), active_color.g(), active_color.b(), (255.0 * anim_alpha) as u8)); + + // Top neon specular edge highlight for intense vibrancy + painter.line_segment( + [egui::pos2(toast_rect.left(), toast_rect.bottom() - bar_h), egui::pos2(toast_rect.left() + bar_w, toast_rect.bottom() - bar_h)], + Stroke::new(1.0_f32, Color32::from_rgba_unmultiplied( + (active_color.r() as u16 + 80).min(255) as u8, + (active_color.g() as u16 + 80).min(255) as u8, + (active_color.b() as u16 + 80).min(255) as u8, + (240.0 * anim_alpha) as u8, + )), + ); + + // Laser-sharp white leading tip indicator if bar_w > 2.0 { painter.line_segment( - [egui::pos2(toast_rect.left() + bar_w, toast_rect.bottom() - bar_h), egui::pos2(toast_rect.left() + bar_w, toast_rect.bottom())], - Stroke::new(1.5_f32, Color32::from_rgba_unmultiplied(255, 255, 255, (220.0 * anim_alpha) as u8)), + [egui::pos2(toast_rect.left() + bar_w, toast_rect.bottom() - bar_h - 1.0), egui::pos2(toast_rect.left() + bar_w, toast_rect.bottom())], + Stroke::new(2.0_f32, Color32::from_rgba_unmultiplied(255, 255, 255, (255.0 * anim_alpha) as u8)), ); } @@ -2776,18 +2798,40 @@ impl eframe::App for ShadowPlayToastApp { egui::StrokeKind::Inside, ); - // 5. Animated Countdown Timer Line (bottom edge - high visibility) + // 5. Animated Countdown Timer Line (bottom edge - vibrant accent glow) let progress = 1.0 - (elapsed / total_dur).clamp(0.0, 1.0); let bar_h = 3.5_f32; - let bar_track = egui::Rect::from_min_size(egui::pos2(rect.left(), rect.bottom() - bar_h), egui::vec2(320.0, bar_h)); - painter.rect_filled(bar_track, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(255, 255, 255, (30.0 * anim_alpha) as u8)); let bar_w = (320.0 * progress).max(0.0); + + // Track: glowing tinted accent baseline + let bar_track = egui::Rect::from_min_size(egui::pos2(rect.left(), rect.bottom() - bar_h), egui::vec2(320.0, bar_h)); + painter.rect_filled(bar_track, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(active_color.r(), active_color.g(), active_color.b(), (45.0 * anim_alpha) as u8)); + + // Ambient vibrant glow above bar + let glow_h = 3.0_f32; + let glow_rect = egui::Rect::from_min_size(egui::pos2(rect.left(), rect.bottom() - bar_h - glow_h), egui::vec2(bar_w, glow_h)); + painter.rect_filled(glow_rect, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(active_color.r(), active_color.g(), active_color.b(), (50.0 * anim_alpha) as u8)); + + // Solid vibrant core bar let bar_rect = egui::Rect::from_min_size(egui::pos2(rect.left(), rect.bottom() - bar_h), egui::vec2(bar_w, bar_h)); painter.rect_filled(bar_rect, CornerRadius::ZERO, Color32::from_rgba_unmultiplied(active_color.r(), active_color.g(), active_color.b(), (255.0 * anim_alpha) as u8)); + + // Top neon specular edge highlight for intense vibrancy + painter.line_segment( + [egui::pos2(rect.left(), rect.bottom() - bar_h), egui::pos2(rect.left() + bar_w, rect.bottom() - bar_h)], + Stroke::new(1.0_f32, Color32::from_rgba_unmultiplied( + (active_color.r() as u16 + 80).min(255) as u8, + (active_color.g() as u16 + 80).min(255) as u8, + (active_color.b() as u16 + 80).min(255) as u8, + (240.0 * anim_alpha) as u8, + )), + ); + + // Laser-sharp white leading tip indicator if bar_w > 2.0 { painter.line_segment( - [egui::pos2(rect.left() + bar_w, rect.bottom() - bar_h), egui::pos2(rect.left() + bar_w, rect.bottom())], - Stroke::new(1.5_f32, Color32::from_rgba_unmultiplied(255, 255, 255, (220.0 * anim_alpha) as u8)), + [egui::pos2(rect.left() + bar_w, rect.bottom() - bar_h - 1.0), egui::pos2(rect.left() + bar_w, rect.bottom())], + Stroke::new(2.0_f32, Color32::from_rgba_unmultiplied(255, 255, 255, (255.0 * anim_alpha) as u8)), ); }