Files
imajviewer/docs/performance_llvmpipe_issue.md

3.8 KiB
Raw Permalink Blame History

Performans: llvmpipe (Yazılımsal Render) Altında Efekt Donmaları

Tarih: 2026-08-03 Durum: Uygulandı (ölçüm sonuçları bölüm 3'te)

1. Teşhis

  • VM'de donanım GPU'su yok: glxinfo -BDevice: llvmpipe (LLVM 21.1.8, 128 bits), /dev/dri yok. Tüm çizim 4 CPU çekirdeğinde LLVM ile yapılıyor.
  • Efekt sürüklemesi (contrast/saturation/brightness/rotate): her PointerMoveEvent doğrudan setState → tüm görsel katman ColorFiltered ile yeniden boyanıyor.
  • Fare sürüklemesinde olay hızı 100-250+/sn; llvmpipe kare süresi 20-100ms+. Üretim > tüketim → kuyruk birikmesi → UI thread %100 → donma. Kuyruk boşalınca arayüz yakalıyor ("1 dk sonra normale döndü").
  • Rotate'in önce kilitlenmesi normal: Transform ikinci bir composite geçişi ekliyor. Contrast aynı duvara galeri akışıyla (daha büyük görseller, dolu ImageCache) çarptı.

2. Uygulanan Değişiklikler

Render izolasyonu ve kare hızı eşitleme — lib/widgets/image_canvas.dart

  • Pointer move / scroll / pan / efekt işleyicilerinden setState kaldırıldı.
  • ValueNotifier<int> _renderTick + ValueListenableBuilder — görsel katman yalnızca tick ile yeniden kurulur.
  • SchedulerBinding.instance.scheduleFrameCallback — saniyede en fazla 1 rebuild/kare (ekran yenileme hızıyla sınırlı); olaylar kareye eşitlenir, kuyruk birikmez.
  • RepaintBoundary — efekt repaint'i pencere/title bar/üst widget render'ını etkilemez.
  • Not: per-efekt ValueNotifier yerine tek tick notifier kullanıldı. Nedeni: ValueListenableBuilder her değer değişiminde yeniden kurulur (olay hızında kalır); throttling için tek noktadan kare başına tick gerekli.

Image pipeline — lib/widgets/image_canvas.dart + lib/services/image_manager.dart

  • ResizeImage.resizeIfNeeded(cacheWidth: viewport×2) — yüksek çözünürlüklü görseller görüntüleme boyutunun ~2 katıyla sınırlı decode edilir: decode süresi, bellek ve llvmpipe CPU yükü düşer. (Zoom 2x'e kadar net; ötesi canlı önizleme için kabul edilen takas.)
  • configureCache: 1000 görsel / 1GB → 16 görsel / 256MB.
  • Galeri/klasör geçişinde imageCache.clear() — canlı (gösterilen) görsel korunur, eski klasörün decode edilmiş ui.Image nesneleri bellekten düşer.

3. Ölçüm (llvmpipe)

Ölçüm yöntemi: 4000×3000 PNG açıldı; kullanıcı elle contrast / saturation / brightness sürüklemeleri yaptı. Kare süreleri addTimingsCallback ile (geçici enstrümantasyon, sonra kaldırıldı), CPU pidstat ile örneklendi.

Metrik Değer
Kare sayısı (contrast turu) 76
build ort / max 3.9 ms / 78 ms
raster ort / max 15.1 ms / 52 ms
Kare sayısı (sat/brightness turu) 133
build ort / max 3.0 ms / 82 ms
raster ort / max 14.1 ms / 48 ms
CPU — boştayken %0-14
CPU — aktif sürüklemede %100-163 (1-1.6 çekirdek)

Değerlendirme: raster ort. ~14-15 ms (16.7 ms kare bütçesinin altında), sürükleme sırasında maksimum ~50 ms → ara sıra kare atlanır ama kuyruk birikmesi ve dakikalarca süren donma yok. CPU 4 çekirdeğin tamamını asla doyurmuyor (önceki durumda sürükleme anında tam doygunluk + 1 dk donma vardı).

4. VM Sistem Gereksinimleri (öneri — uygulama dışı)

llvmpipe tamamen yazılımsal; kalıcı çözüm VM tarafında donanım hızlandırmasıdır:

  • virtio-gpu + VirGL: QEMU/libvirt'ta -device virtio-vga-gl / virtio-gpu-gl (mesa'nın VirGL yoluyla hızlandırılmış GL'si). /dev/dri görünür hale gelir.
  • PCIe Passthrough: gerçek GPU'yı VM'e bağlama (en yüksek performans, donanım gerektirir).
  • Bu olmadan uygulama yukarıdaki yazılımsal önlemlerle çalışır, ancak büyük görsellerde efekt sürüklemesi yine de kare atlayabilir.