# 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 **açı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ı açı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ır** — `HardwareKeyboard` handler'ına, X11 Shift güvenilmezliğine, Alt yutma pitfall'ına gerek kalmaz | | Render maliyeti (ilk derleme sonrası) | **Ancak tasarımla düşer** — `onChangeEnd`'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) Açı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.high` → `FilterQuality.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?)