Files
imajviewer/docs/rapor-pan-kilitleme-nuks.md

12 KiB
Raw Blame History

Rapor — Efekt Uygulanmış Görselde Pan Sırasında Kilitlenme (Nüks)

Tarih: 2026-08-06 Durum: Analiz — hipotezler hazır, açık sorular kullanıcı yanıtını bekliyor

1. Semptom (yeni bildirim)

  • Donma sorunu yeniden ortaya çıktı — bu kez "diğer bilgisayarda" (VM değilse ortamı bilinmiyor; önceki testler Xubuntu VM + llvmpipe idi).
  • Tetikleyici farklı: önceki nüksler efekt sürüklemesi sırasında idi (contrast/saturation/brightness/rotate drag). Şimdi efekt uygulanmış durumda (değerler sabit) iken PAN yaparken kilitlenme.
  • "Olmadık zamanlarda" — rastgele zamanlarda, her pan'da değil.

2. Önceki Teşhisler ve Çözümler (kayıt özeti)

Tarih Teşhis Çözüm Durum
03 Ağu Kuyruk birikmesi: pointer event hızı (100-250/sn) > llvmpipe kare hızı → setState her event'te → UI thread %100, 30-60sn donma _markRenderDirty() frame-throttle (kare başına max 1 rebuild) + ResizeImage (viewport×2) + provider memoize + cache 16/256MB + galeri geçişinde imageCache.clear() Uygulandı, ölçüldü (raster ort ~15ms, max ~50ms, kuyruk birikmesi yok)
06 Ağu İlk kullanım shader derlemesi (B1): process başına soğuk Skia/GL cache; ilk ColorFiltered/Transform kullanımı 15sn-1dk derleme Shader warmup: açılışta gizli Opacity(0) katmanla filtre + rotate shader'larını derlet Uygulandı (release build + kurulum 06 Ağu)

2b. Kullanıcı Yanıtları (2026-08-06, ikinci bildirim)

  • Ortam: gerçek makineMesa Intel(R) HD Graphics 3000 (SNB GT2) (Sandy Bridge iGPU, 2011). mesa i965 driver GLSL'i LLVM ile CPU'da derler → karmaşık shader varyantları 30sn'ye çıkabilir. 12GB RAM, son sürüm kurulu.
  • Test sonuçları (kullanıcı):
    • Resim büyükse (dosya ~1MB+) oluyor; küçük görselde olmuyor.
    • Fill modda olmuyor, fit modda oluyor.
    • İlk açılışta fit moda geçip rotate edilirse oluyor — tek seferlik, sonra tekrar değil (kullanıcı "sanırım" ile ifade etti, teyit beklenecek).
  • Bu bilgiler Aday F'yi doğruluyor: warmup 1x1 gizli katmanda yapılıyor, gerçek kullanımın (büyük doku + fit BoxFit.contain + rotate + ColorFiltered) shader varyantı warmup'ta derlenmiyor → ilk gerçek kullanımda 30sn derleme.
  • Aday A (ColorFiltered CPU filtrelemesi) ve C (bellek) elendi — GPU var, RAM bol.
  • EKLENTİ (kullanıcı kurcalayınca): Fill modda da oluyor; "biraz zorlayınca aynı resimde tekrar oldu" — yani tek seferlik DEĞİL. Bu Aday F'yi (ilk kullanım derlemesi, cache'li kalır) zayıflatıyor; varyant sayısı fazlaysa her yeni kombinasyon yeni derleme olabilir (aşağıda Aday H/I).

Her iki çözüm de mevcut kodda aktif: image_canvas.dart_markRenderDirty, provider memoize (_cachedProvider), _buildWarmupLayer().

3. Yeni Analiz — Neden "Efekt + Pan" Kilitlenir?

Pan akışı: _onPanUpdate_tx/_ty += delta_clamp()_markRenderDirty().

Aday A — ColorFiltered her pan frame'inde tüm görseli CPU'da filtreliyor

  • Efekt aktifken (hasFilter == true) her rebuild'te ColorFilteredImage tüm görsel 5x4 matrisle filtrelenir. Pan'da translate değişir → her frame'de yeniden boyama + filtreleme.
  • 4000×3000 görsel ≈ 12M piksel; llvmpipe'ta filtre + ölçekleme + translate ≈ 20-60ms/kare. FPS 15-50'ye düşer → "takılma" hissi.
  • _markRenderDirty kuyruk birikmesini engeller ama kare başına maliyet yüksekse düşük FPS kalıcı olur. Büyük görsel + zayıf makinede bu "kilitlenme" gibi algılanabilir.
  • Rotate aktifse (pan serbest, _clamp erken return) Transform + ColorFiltered birlikte — en ağır kombinasyon.

Aday B — _clamp() pan event hızında findRenderObject() çağırıyor

  • _onPanUpdate her event'te _clamp() çağırır; fit modda _clamp() içinde _imageKey.currentContext?.findRenderObject() (satır 77) pointer hızında (throttle'ın DIŞINDA) render tree sorgusu yapar. Pan event'leri 100-250/sn → gereksiz layout/tree traversal yükü. Kilitlenme üretmez ama takılmayı artırır.

Aday C — Bellek/GC baskısı ("olmadık zamanlarda" rastgeleliğin en iyi adayı)

  • Rastgele kilitlenme imzası GC/swap'e işaret eder. "Diğer bilgisayar"da RAM azsa (8GB altı) veya başka işler varsa: büyük görsel decode + 256MB cache + pan sırasında GC pause → kısa ama algılanabilir donmalar.
  • Pan sırasında yeni decode yok (memoize) → cache baskısı düşük; ama makine belleği dar ise OS seviyesinde swap thrashing olabilir.

Aday D — Eski binary / farklı ortam ("diğer bilgisayar")

  • "Diğer bilgisayarda" kurulu sürüm bilinmiyor. Eski .deb (warmup/memoize öncesi) kuruluysa sorun zaten açıklanır. Ayrıca o makinede donanım GPU'su VARSA teşhis tamamen değişir (llvmpipe değil) — ColorFiltered donanımda ucuzdur, o zaman aday C veya farklı bir sebep aranır.

Aday E — Pan sırasında yeni frame kuyruğu (zayıf)

  • scheduleFrameCallback kare başına 1 callback garanti eder; kare süresi uzarsa FPS düşer ama kuyruk birikmez (03 Ağu ölçümü). Kilitlenme üretmez.

Aday F — Warmup varyant eksikliği: 1x1 katman gerçek kullanımı derlemiyor

  • Warmup (_buildWarmupLayer) 1x1 boyutunda gizli katmanla filtre + rotate shader'larını derletiyor. Skia/GL'de shader varyantları doku boyutu, sampling modu, filtre kalitesi gibi parametrelere göre ayrı derlenir.
  • Gerçek kullanımda büyük görsel (4000x3000) + FilterQuality.high + BoxFit.cover/contain + ColorFiltered + pan/zoom Transform — bu kombinasyonun shader'ı 1x1 warmup'ta derlenenle aynı varyant olmayabilir → ilk gerçek kullanımda derleme yine olur → 30sn kilitlenme.
  • "Efekt uygulanmışken pan yaparken" tetikleyicisi: pan/zoom + ColorFiltered birlikte ilk kez kullanıldığında varyant derlenir; sonrası cache'li → "olmadık zamanlarda" ve "her pan'da değil" imzası birebir uyuyor.
  • GPU'da shader derleme süresi genelde ms seviyesindedir; zayıf/iç ekran kartı + mesa/LLVM backend ile 30sn'ye çıkabilir. "İyi kötü ekran kartı" ifadesi bu olasılığı güçlendiriyor.
  • Warmup'ın gerçek boyutla yapılması gerekir: gizli katman 1x1 yerine mevcut görselin boyutunda (veya viewport boyutunda) olmalı; ayrıca pan/zoom Transform'u da warmup'a dahil edilmeli.

Aday G — Gerçek GPU driver / doku sınırı

  • Zayıf GPU'da büyük doku (12MP RGBA ≈ 48MB) + ColorFiltered → driver'da aşırı yavaş path veya GL sync beklemesi. glxinfo -B renderer string'i kritik (NVIDIA nouveau / AMD radeon / Intel / llvmpipe?).

Aday H — Skia varyant cache dolması / her kombinasyon yeni derleme

  • "Aynı resimde tekrar oldu" → tek seferlik derleme değil. Skia'da her farklı kombinasyon (zoom seviyesi × rotate açısı × efekt değeri × fit/fill × filtre kalitesi) farklı shader varyantı üretebilir; varyant cache'i sınırlıysa (LRU) eski varyant atılır → aynı kombinasyon tekrar kullanılınca YENİDEN derlenir → 30sn. "Zorlayınca" = çok varyant üretmek = cache'i doldurmak = tekrar derleme.
  • Bu, "ilk kullanımda" + "sonra tekrar" imzasını birlikte açıklayan hipotez.

Aday I — Intel HD 3000 GL sync / doku upload darboğazı

  • Sandy Bridge iGPU paylaşımlı bellek kullanır; büyük doku upload + ColorFiltered
    • Transform her frame'de GL sync bekleyebilir. _markRenderDirty throttle frame üretimini sınırlar ama raster thread yavaş kalırsa UI thread frame kuyruğunu tüketemez → 30sn'lik görünür donma (olaylar işlenir, görsel gecikir — önceki raporlardaki imza).
  • Doku boyutuna duyarlılık (1MB+ görsel) + fill/fit farkı (BoxFit.cover kırpar → daha küçük etkin doku; contain → tam doku işlenir) bu hipotezle uyumlu.
  • Intel HD 3000'de LIBGL_ALWAYS_SOFTWARE=1 (llvmpipe) ile karşılaştırma testi ayırt edici: GL sync sorunu ise software'de farklı davranır.

4. Hipotez Önceliklendirme

Aday ıkladığı Gücü
A (ColorFiltered her frame) Efekt+pan takılması, "kilitlenme" hissi (efekt açıkken kaçınılmaz maliyet; azaltılabilir)
B (_clamp findRenderObject) Ek pan yükü (kolay düzeltilir)
C (bellek/GC) "Olmadık zamanlarda" rastgelelik (makine belleği bilinmiyor)
D (ortam/eski binary) Tamamen farklı kök (önce doğrulanmalı)

5. Önerilen Çözüm Yolları (rapor onayı sonrası)

Seçenek 1 — Pan sırasında filtre maliyetini azalt (Aday A)

  • Efekt aktifken pan/zoom sırasında FilterQuality.highFilterQuality.medium (görsel kalite farkı minimal, llvmpipe yükü düşer) — tek satır.
  • Pan sırasında cacheWidth'i düşürme (memoize zaten sabit tutuyor) — gerek yok.
  • Alternatif: pan sırasında geçici düşük çözünürlük önizlemesi (mevcut görseli küçük boyutta filtrele) — karmaşık, önce basit yol denenir.

Seçenek 2 — _clamp() içindeki findRenderObject yükünü azalt (Aday B)

  • _imageKey.currentContext?.findRenderObject() yalnızca fit modunda lazım; pan'da _vpSize değişmediği sürece tekrar sorgulamaya gerek yok — _clamp'in render sorgusunu her pan event'inde değil, sadece layout değişince yap. (Dikkatli: rotate varken _clamp zaten erken return ediyor; fit modunda kilitlenme riski yok.)

Seçenek 3 — Ortam doğrulaması (Aday D) — rapor öncesi şart

  • "Diğer bilgisayar"da: glxinfo -B | grep -i renderer (llvmpipe mi GPU mu), free -h, kurulu sürüm (.deb tarihi / imajviewer --version yoksa binary timestamp). Ayrıca aynı görselle bu VM'de tekrar dener misin — nüks VM'de de mi, sadece diğer makinede mi?

6. Kalan Açık Sorular

  1. "Diğer bilgisayar" hangisi — başka VM mi, gerçek makine mi? Donanım GPU'su var mı (glxinfo -B çıktısı)?
  2. O makinede kurulu sürüm: son .deb (2026-08-06 sonrası) mi, yoksa eski mi?
  3. Kilitlenme süresi ne kadar — 1-2sn mi, 10sn+ mı, yoksa "kapatmak zorunda kaldım" mı?
  4. Hangi efekt uygulanmışken pan yapıyorsun — contrast mi, rotate mi (rotate en ağırı)?
  5. Görsel boyutu ne — büyük fotoğraf mı (4000px+), küçük ekran görüntüsü mü?
  6. Aynı görselle bu VM'de (llvmpipe) pan dener misin — nüks VM'de de oluyor mu?

7. Ölçüm Planı (onaylanırsa)

Skill'deki references/llvmpipe-perf-measurement.md akışı: geçici addTimingsCallback (FRAME build/raster süreleri) + pidstat CPU. Ölçüm sırasında kullanıcı elle pan yapar ("sen aç ben yaparım"). Enstrümantasyon geçicidir ve sonrası temizlenir. VM'de ölçüm yapılabilir; "diğer bilgisayar"da enstrümantasyonlu build kurmak gerekir (kullanıcı onayı şart).

8. Sonuç

İki önceki çözüm (throttle + warmup) doğru teşhislere dayanıyordu ve ilk iki donma imzasını çözdü. Yeni imza farklı: efekt SABİT iken pan. En güçlü açıklama Aday A (ColorFiltered'in her pan frame'inde tam görseli CPU'da filtrelemesi) — özellikle büyük görsel + zayıf makinede "kilitlenme" hissi yaratır. Rastgelelik için Aday C (bellek/GC) ve Aday D (ortam) doğrulanmalı. Kullanıcı yanıtları gelince rapor güncellenir ve çözüm yolları netleşir.

9. Kapanış Notu (2026-08-06)

Kullanıcı donma sırasında top -b -d 1 ölçümü başlattıktan sonra nüks olmadı (ne denediyse kilitlenme/takılma görülmedi). Nüks koşulları belirsiz; konu bu raporla askıda bırakıldı — kullanıcı talep ederse yeniden açılır. Olası ipucu: ölçüm sırasında sistem yükü değişince davranış değişti (Aday I — GL sync/GPU yükü ile ilişkili olabilir; kesin teşhis yapılmadı).