# 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 -B` → `Device: 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 _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.