Files
imajviewer/docs/rapor-sag-tik-donma-analizi.md

9.9 KiB
Raw Permalink Blame History

Rapor — Sağ Tuş Efektlerinde Donma Analizi ve Slider UI Değerlendirmesi

Tarih: 2026-08-06 Durum: Analiz — B teşhisi netleşti, uygulama bekliyor

1. Semptom

  • Sağ tuş ile kullanılan özelliklerde (contrast / saturation / brightness / rotate) uygulama geçici olarak donuyor.
  • Donma süresi 15sn - 1dk arası (kısa değil, ciddi bir tek seferlik maliyet).
  • Release build kullanılıyor (.deb'den kurulu) → Dart JIT hipotezi elendi, donma release AOT'ta da var.
  • Donma kalıcı değil: kullanıcı "kapatayım mı" diye soruyor, "bekle" deyince kendiliğinden düzeliyor.
  • Donma sırasında yapılan işlemler (sağ tık + aşağı çekme, pan) donma açıldığında yapılmış olarak görülüyor — olaylar işleniyor, sadece görsel gecikiyor.
  • Sadece çok pencereli (multi-instance) kullanımda oluyor, tek pencerede olmuyor.
  • Her pencere açılışında ilk efekt kullanımında bir kez oluyor; o donma açıldıktan sonra aynı pencerede tekrar olmuyor.
  • Eskiden sadece rotate'te olurdu; şimdi tüm efektlerde oluyor, en çok rotate'te.
  • Donan pencere kilitli kalıyor; diğer pencereler normal çalışıyor. Task bardan kapatılabiliyor.
  • Kullanıcı şüphesi: klavye tuşlarının (Ctrl/Shift) basılı tutulmasıyla ilgili olabilir — "farklı bir şey olma ihtimali yüksek".
  • Soru: bu özellikleri ılan kutu içinde slider UI ile yapsak takılmalar çözülür mü?

2. Mevcut Mimari (lib/widgets/image_canvas.dart)

Katman Mekanizma
Mod seçimi _onPointerDown: sağ tık + _ctrlPressed/_shiftPressed state'i → contrast (yok) / rotate (Shift) / saturation (Ctrl) / brightness (Ctrl+Shift)
Modifier takibi HardwareKeyboard.instance.addHandler(_onHardwareKey) — global, return false (yutmaz)
Değer güncelleme _onPointerMove: dy * sensitivity_markRenderDirty()
Render eşitleme _renderTick ValueNotifier + scheduleFrameCallback — kare başına max 1 rebuild
Image pipeline ResizeImage.resizeIfNeeded(cacheWidth: viewport×2) + provider memoize (03 Ağu fix)
Efekt ColorFiltered (birleşik 4x5 matrix, cache'li) + rotate için Transform
Varsayılan _isFilled = true (BoxFit.cover), FilterQuality.high

3. Kök Neden Analizi — Geliştirilmiş Teşhis (kullanıcı geri bildirimiyle)

Kullanıcının verdiği yeni bilgiler adayları eliyor:

Gözlem Hangi adayı eler/güçlendirir
Donma geçici, kendiliğinden düzeliyor Aday A (kalıcı frame üretimi durması) elendi → B güçlendi
Donma sırasında yapılan işlemler sonradan görülüyor UI thread olayları işliyor; sadece render/raster geride → Aday A elendi, B güçlendi
Sadece çok pencerede oluyor Process başına soğuk kaynak → B güçlendi
Her pencerede İLK efekt kullanımında bir kez, sonra tekrar olmuyor İlk kullanım maliyeti — shader derleme / kaynak ısınması → B1 (aşağıda)
Eskiden sadece rotate, şimdi tüm efektlerde Efekt başına ilk-kullanım maliyeti → B1
En çok rotate'te Rotate en pahalı (Transform + ColorFiltered birlikte) → B

Teşhis: B1 — İlk Kullanım Render Maliyeti (shader derleme + kaynak ısınması)

Semptom setinin tamamınııklayan tek hipotez:

  • Her pencere ayrı process (multi-instance). Her process'in kendi Skia/GL kaynakları soğuk başlar.
  • İlk kez ColorFiltered (color matrix shader) ve/veya Transform (rotate) kullanıldığında llvmpipe shader'ı derler + ilgili render path'i kurar — bu tek seferlik maliyet 1-10sn+ sürebilir (yazılımsal render, 4 CPU çekirdeği).
  • Sonraki kullanımlarda shader cache'li → donma tekrar etmez. "Bir kere oluyor, açıldıktan sonra tekrar olmuyor" = tam olarak bu.
  • Tüm efektlerde olması: brightness (03 Ağu'da eklendi, yeni birleşik 4x5 matrix) dahil her efekt kendi shader'ını ilk kez derliyor. Eskiden sadece rotate'te olması: o günlerde contrast/saturation zaten ısınmış/kullanılmıştı; rotate her oturumda en son eklenen ve en pahalı olandı.
  • En çok rotate'te: rotate iki shader path'ini birleştirir (ColorFiltered matrix + Transform composite) → en uzun ilk derleme.
  • Çok pencerede olması: her pencere soğuk başlar → her pencerede ilk efekt kullanımında ayrı donma. Tek pencerede donma tek seferlik olduğu için "sorun yok" gibi görünür.

Aday B — llvmpipe raster thread uzun kare (arka plan maliyeti)

  • Donma anında UI thread çalışıyor (işlemler işleniyor) ama görsel gecikiyor → raster/kompozisyon kuyruğu geride.
  • llvmpipe'ta her kare 15-50ms (03 Ağu ölçümü); ilk shader derlemesi bu kareleri 100x şişirir.
  • B1'in "ilk kullanım" tetikleyicisi, B'nin "uzun kare" mekanizması — ikisi aynı olayın iki yüzü: soğuk kaynakla ilk efekt frame'i çok pahalı.

Aday C — Bellek baskısı / swap thrashing

  • Çok pencerede olması C'yi güçlendirir (her process ayrı decode + doku). Ama "tekrar olmuyor" imzası C ile tam uymuyor (bellek baskısı her seferinde olur). İkincil faktör olabilir.

Aday D — _clamp() build sırasında findRenderObject()

  • Donma yapmaz (null döner), performans etkisi minimal. Kırmızı ringa.

4. Klavye Hipotezi Değerlendirmesi (kullanıcının şüphesi)

Donmaya klavye neden olmuyor. _onHardwareKey handler'ı sadece iki boolean set/clear ediyor — maliyeti ihmal edilebilir, render tetiklemiyor, event yutmuyor. Kullanıcının "farklı bir şey" sezgisi doğru.

Ancak klavye yanlış mod tetikleme (takılma hissi) üretebilir:

  • X11'de Shift durumu pointer event sırasında güvenilmez (skill'de belgeli: isShiftPressed false dönebilir). _onHardwareKey ile takip doğru çözüm ama yine de key repeat / focus kaybı durumlarında state bozulabilir.
  • Shift basılıyken sağ tık → kullanıcı farkında olmadan rotate modu açılır → en pahalı efekt + beklenmedik davranış → "takılıyor" hissi.
  • Alt + tık XFCE WM tarafından yutulur (bilinen pitfall) — zaten Ctrl/Ctrl+Shift'e geçilmişti.

5. Slider UI Değerlendirmesi (kullanıcının önerisi)

Kısa cevap: B1 (ilk kullanım shader derlemesi) teşhisi doğruysa, slider UI donmayı ÇÖZMEZ — çünkü donma render maliyetinden değil, ilk kullanımdaki tek seferlik shader derlemesinden kaynaklanıyor. Slider ile contrast'ı ilk kez açtığın anda yine aynı shader derlenecek ve yine aynı donma olacak. Ama doğru tasarımla yine de değerli:

Bileşen Slider UI etkisi
İlk kullanım shader derlemesi (B1) Çözmez — shader yine o an derlenir. Çözüm warmup (aşağıda)
Olay hızı Aynı kalır — slider da sürüklerken onChanged pointer hızında çağrılır. Ama ilk derleme bittikten sonra gerisi akıcıdır
Mod bilinirliği Çözer — hangi modda olduğun görünür; gizli modifier mapping'i biter. "Takılıyor" hissinin büyük kısmı modun ne olduğunu bilmemektir
Klavye bağımlılığı Tamamen kaldırırHardwareKeyboard handler'ına, X11 Shift güvenilmezliğine, Alt yutma pitfall'ına gerek kalmaz
Render maliyeti (ilk derleme sonrası) Ancak tasarımla düşeronChangeEnd'de uygula + sürükleme sırasında düşük çözünürlüklü önizleme (küçük cacheWidth) yapılırsa render başına maliyet ciddi düşer

Sonuç: Slider UI tek başına "sihirli çözüm" değil. Donmanın asıl çözümü B1'e karşı: shader warmup + ilk derlemeyi kullanıcı etkileşiminden önce yaptırmak.

6. Önerilen Çözüm Yolları (B1 teşhisine göre)

Seçenek 1 — Shader Warmup (ilk derlemeyi öne çek) UYGULANDI (2026-08-06)

ılışta, kullanıcı daha sağ tıka basmadan efekt shader'ları derletilir:

  • ImageCanvas.initState → ilk frame sonrası _startWarmup().
  • Görünmez 1x1 gizli katman (_buildWarmupLayer): adım 1'de ColorFiltered (filtre shader'ı), adım 2'de ColorFiltered + Transform rotate (rotate shader'ı) render edilir; sonra _warmupDone = true ile katman kaldırılır.
  • Kullanıcı ilk sağ tıka bastığında shader'lar hazırdır → donma hissi kaybolmalı.
  • Maliyet: pencere açılışında 2-3 ekstra gizli frame (arka planda, etkileşim yokken).
  • Not: çok pencerede her process kendi warmup'ını yapar — aynı mantık.
  • Doğrulama: release build + kurulum yapıldı (2026-08-06). Kullanıcı test edecek — ilk sağ tık donması yoksa teşhis doğrulanır.

Seçenek 2 — Release build ile test (JIT yükü teyidi)

  • GÜNCELLEME: Kullanıcı zaten release build kullanıyor (.deb'den kurulu) — JIT hipotezi elendi. Donma release AOT'ta da oluyor.
  • 15sn-1dk süre, llvmpipe'ta ilk render path kurulumunun (shader derleme + layer/doku hazırlığı) toplam maliyeti olabilir; "bir kez oluyor, tekrar olmuyor" imzası korunuyor.

Seçenek 3 — Rotate maliyetini düşür

  • Rotate aktifken FilterQuality.highFilterQuality.medium (rotate sırasında görsel kalite farkı minimal, maliyet düşer).
  • Transform + ColorFiltered aynı anda aktifken tek composite path önerilir (mevcut yapı zaten tek ColorFiltered kullanıyor).

Seçenek 4 — Slider UI (UX netliği, donma çözümü değil)

  • Donma B1'den kaynaklanıyorsa slider UI donmayı çözmez; ama mod bilinirliği + klavye bağımsızlığı sağlar.
  • Warmup (Seçenek 1) uygulandıktan sonra slider UI istenirse eklenir — ikisi birlikte: donma yok + kullanım net.

7. Kalan Açık Sorular

  1. Donma süresi yaklaşık ne kadar — 1-2sn mi, 10sn+ mi? (B1 shader derleme süresi tahminini doğrular)
  2. Debug build mi kullanıyorsun (install.sh ile kurulan), yoksa release mi? → Seçenek 2'yi doğrular
  3. Slider UI hâlâ isteniyor mu, yoksa önce donma çözümü mü? (Sıra: warmup → slider opsiyonel)
  4. Warmup için "açılışta arkada 1-3sn hazırlık" kabul edilir mi? (Alternatif: ilk efekt kullanımında 1 kez donma kabul edilir mi?)