HTML5 Canvas · Performans ve optimizasyon
Yeniden çizim maliyeti: tuvalde piksel başına ödenen fiyat
Her drawImage, dolgu veya gölgeli yol, tarayıcıda yeniden rasterize /
birleştirme işi tetikler; tuval ne kadar büyük ve işlemler ne kadar pahalıysa kare
süresi o kadar şişer. Bu sayfa «ne sıklıkla tüm ekranı silip baştan çizmeliyim?» ve «hangi
bölgeleri gerçekten güncelledim?» sorularını Canvas 2D bakış açısıyla sabitler — tam
clearRect ile
dirty rectangle ayrımı, katman tuval stratejisi ve bağlam özelliklerinin
maliyet ipuçlarını içerir. Zihinsel çerçeve
Update vs
render ve
Temizle ve
yeniden çiz sayfalarıyla birlikte okunmalıdır.
Çağrı birleştirme ve toplu çizim Batching mantığı başlığında; boyutlandırma ve piksel oranı Yeniden boyutlandırma mantığı ile ilişkilidir.
Özet: maliyet kaynakları
| Kaynak | Etki | Azaltma |
|---|---|---|
| Tuval alanı | Silme ve dolgu piksel sayısı | Kısmi temizlik / katman |
| Üst üste çizim | Aynı piksel tekrar işlenir | Sıra ve opaklık disiplini |
| Gölge, süzgeç | Ek geçişler | Sınırlı kullanım, önbake |
save /
restore
|
Yığın maliyeti | Dar kapsam |
| Gereksiz kare | Sabit sahne yine çizilir | Kirli / bayrak |
Tuval yeniden çizimi ve piksel bütçesi
Canvas 2D’de «bir kare» çoğu zaman tüm hedef yüzeyin güncellenmesi anlamına gelmez; pratikte
ise basit oyunlar her turda clearRect(0,0,w,h) ile başlayıp her şeyi yeniden
çizmeyi seçer. Bu, kodu sadeleştirir ama piksel sayısı (
genişlik × yükseklik × cihaz piksel oranı ) ile doğru orantılı bir maliyet doğurur — sahne
karmaşık değilken bile çözünürlük büyüdükçe süre büyür. Tamponu baştan sona silmek, aynı
çözünürlükte her piksele en az bir yazma (ve genelde ikinci bir tam çizim turu) demektir;
ölçümde canvas.width /
height (cihaz pikselleri) doğrudan bütçe alanıdır.
«Yeniden çizim maliyeti» hem kaç kez çizdiğiniz hem de ne kadar alanı etkilediğiniz ile belirlenir. İnce taneli parçacık, ışık saçan çizgiler aynı piksele defalarca yazılabilir; her geçiş birleştirme kurallarına göre ek iş yükü taşır. Bu «üst üste boyama» ( overdraw ) zengin görünen ama nesne sayısı düşük sahnelerde bile süreyi şişirebilir. Bu yüzden üretimde profil ( tarayıcı performans paneli: ana iş parçacığı, boyama / raster adımları ) ile gerçek darboğazı ölçmeden optimizasyon sırası seçilmemelidir.
Kare yönetimi ile uyum: bütçeyi kare başına milisaniye cinsinden düşünmek, redraw stratejisini ürün kararı haline getirir — özellikle mobilde. Örneğin 60 kare / saniye hedefinde yaklaşık 16,7 ms içinde fizik, girdi ve oyun mantığı da pay alır; çizime kalan pay yazılı tanımlandığında hangi optimizasyonun erken, hangisinin zorunlu olduğu netleşir.
Tam ekran temizlik–yeniden çizim varsayılanı çoğu prototip için yeterlidir; kare süresi bütçeyi aştığında sırayla kirli dikdörtgen, katman, gereksiz kare atlama ve DPR ayarı ( 6. bölüm ) değerlendirilir.
Tam temizlik ve kirli dikdörtgen stratejisi
clearRect hedeflenen bölgeyi şeffaf yapar; tüm tuval yerine yalnız hareket eden
sprite çevresini temizleyip yeniden çizmek piksel sayısını düşürür. Zorluk, kirli bölgenin
sınırlarını doğru birleştirmek ve arka plan (
paralaks katman, dünya döşemesi ) değiştiyse yine genişletmek gerektiğinde ortaya çıkar —
yanlış küçültme iz bırakan parçalar (
görüntü hayaletleri ) üretir. Tipik akış: her değişen öğe için bir dikdörtgen çıkar → kare
boyunca
mergeDirtyRect ile
birleşim kutusunu büyüt → yalnız o kutuda clearRect ve yeniden çizim. Arka plan
statik katmanda tutuluyorsa üst tuvaldeki
kirli alan genellikle daha küçük kalır.
Basit sahnelerde kirli dikdörtgen birleştirme ( birleşim kutusu ) ile yönetilir; parçacık sistemi ve çoklu aktörlerde kutu hızla tüm ekrana yaklaşır — bu durumda tam temizlik daha uygun olabilir. Strateji sahneye göre seçilir; evrensel bir doğru yoktur. Kararı verirken «bir karede kaç aktör kutuyu kirletiyor?» sorusunu piksel bütçesi ile birlikte yanıtlamak, hayal kırıklığını azaltır.
clip ile çizimi kısıtlamak da bir seçenektir; yanlış kullanımda hata ayıklaması
zorlaşır — kırpma yolu da save /
restore yığınına girer; kaybolan çizgiler çoğu zaman «tahta dışında kaldım»
sanısıyla aslında kırpılmış bölgededir. Bağlam sırası
2D bağlam
düşüncesiyle birlikte ele alınmalıdır.
/** İlk kirli alan veya genişletilmiş birleşim kutusu (mantık koordinatlarında). */
function mergeDirtyRect(current, x, y, w, h) {
if (w <= 0 || h <= 0) return current;
if (!current) return { x, y, w, h };
const x2 = Math.max(current.x + current.w, x + w);
const y2 = Math.max(current.y + current.h, y + h);
const nx = Math.min(current.x, x);
const ny = Math.min(current.y, y);
return { x: nx, y: ny, w: x2 - nx, h: y2 - ny };
}
Katman tuval: statik ve dinamik ayırımı
Arka plan ve dünya ızgarası her karede aynıysa bir «arka tuval» (
hafızada ikinci
canvas ) üzerinde bir kez veya nadiren çizip ana tuvalde
drawImage(staticLayer, ...) ile yapıştırmak CPU/GPU-maliyetini düşürür; üstte
hareketli varlıklar küçük kirli bölgelerde güncellenir. Bellek karşılığı: ek piksel tamponu.
Statik katmanın yeniden çizimi genelde seyrek olaylara bağlanır: ilk kurulum, varlık yükü,
yeniden boyut veya bölüm /
seviye değişimi; aradaki karelerde yalnız tek bir drawImage ve üstteki
kısmi yenileme maliyeti ödenir.
Ara katmanlar çoğaldıkça bellek ve senkronizasyon ( her yeniden boyutta üç katmanı da yeniden ölçeklemek ) maliyeti artar — bu yüzden iki veya üç anlamlı katman ( statik / paralaks / dinamik ) ile başlamak pratik üst sınır gibidir. Uygulama boyutuna göre gözden geçirilir.
Offscreen tuval kullanımı ileride Offscreen Canvas sayfasına taşınır; burada yalnız maliyet gerekçesi işaretlenir.
Bağlam durumu ve pahalı özellikler
shadowBlur,
filter,
globalCompositeOperation gibi özellikler caziplidir; açık kaldıkları her
primitif için ek iş yükü doğurabilir. Çizim yardımcınız, geçici olarak açıp kapattığı bu
ayarları yerel bir
save /
restore bloğuna almalı; üretimde «kurulumu unuttum» halleri kare süresinde
görünür. Sürekli stil sıçramasını azaltmak için pahalı modları az çağrıda toplama
batching konusunda işlenir; burada
odak, hangi ayarların açık unutulduğunda ek faturalandığıdır. Benzer üretim tuzakları
8. bölümde madde madde listelenir.
save /
restore yığını derinleştikçe maliyet artar; mümkün olduğunca sığ tutun veya
explicit atamalarla eski değerlere dönün. Özellikle döngü içinde her varlıkta
save üst üste binmesi profilde fark edilir; dönüşümleri geri alma
disiplini
temizle
ve çiz akışıyla çelişmeden yürütülmelidir; yığın derinliğinin kendisi için bkz.
8.
Metin çizimi ve yol sıra doldurma ( stroke/fill ) karmaşık harf formlarında pahalıdır; her karede binlerce dinamik metin etiketi çizmek yerine nadir güncellenen etiketleri önbelleğe almak ( küçük ara tuval veya düşük frekanslı katman ) yaygın profesyonel çözümdür — detay ürün kararıdır; ileri varyantlar Offscreen Canvas ile üretim düzenine taşınır.
Ağır filter zinciri veya büyük shadowBlur rasterı genişletir;
maliyet yalnız «özellik açık mı?» değil, etkilenen dikdörtgenin boyutu ve hedef çözünürlük
ile de büyür. Mobil profilde düşük kare genelde önce burada belirginleşir (
DPR ile çarpılır ).
Gereksiz kare çizimi: kirli bayrak ve atlama
Durum değişmediyse tüm sahneyi yeniden çizmek piksel bütçesini boşa harcar; basit desen:
güncelleme aşamasında değişiklik olduğunda
needsRedraw = true yapılır, çizim döngüsü başında kontrol edilir.
requestAnimationFrame döngüsü yine çalışabilir; fark, çizim dalının erken
dönmesi ve gereksiz clearRect /
draw çağrılarının yapılmamasıdır. Sekme arka plandayken veya
duraklatıldığında çizimi atlamak pil ve ısıyı düşürür —
duraklatma
politikası ile uyumlanır. Bu düzen,
piksel bütçesi ile aynı dilde konuşur:
değişmeyen karede maliyet sıfıra yakınsın.
Yalnız kısmi kirli stratejisi kullanılıyorsa, değişmeyen karelerde bile birleşim kutusu tüm ekrana genişleyebilir — bu durumda bayrak «beni yine de çiz» olarak kalır; telemetri ile gerçekten kazanım olup olmadığını ölçün. Kutunun şişmesi 2. bölümdeki birleştirme mantığından kaynaklanıyorsa, tam ekrana dönmek bazen daha az sürprizlidir.
Bazı tarayıcılarda kullanıcı etkileşimi olmayan sekmeler kare hızını düşürür; animasyon yine de düşünüldüğünde bu, iç mantık güncellemesi ile çizim atlama kararını etkiler. Sekme görünmez kare hızı düşünce «her şey dondu» sanısı doğabilir; simülasyon gerçek zamanlı kalmalıysa bu davranış ürün / test planında açıkça ele alınmalıdır.
function requestRedraw(state) {
state.needsRedraw = true;
}
function consumeRedraw(state) {
const v = state.needsRedraw;
state.needsRedraw = false;
return Boolean(v);
}
Cihaz piksel oranı ve iç çözünürlük
CSS genişliği 800 px, devicePixelRatio = 2 ise arka tampon genelde 1600 piksel
genişlikte çizilir; her
clearRect ile silinen alan iki katına çıkmış olur. Keskin görüntü için
ölçekleme gerekir; performans baskısında hedef oranı düşürmek (
1,5 veya 1 ) bilinçli bir piksel azaltımıdır — bulanıklık ile hız takas edilir.
Mantık dünyası koordinatları ile tuval aygıt pikselleri arasında tutarlı dönüşüm tek yerde tanımlanmalıdır; kirli dikdörtgen hesapları yanlış ölçeklenirse yine hayalet artefaktları oluşur.
Pencere taşınması, tam ekran geçişi gibi olaylar yeniden boyutlandırma ile tetiklenir; ölçek yeniden kurulmadan devam eden redraw yanlış görüntü üretir.
Boyut değişimi ve katman senkronu
Tuval genişliği değiştiğinde hem ana yüzey hem varsa ara tamponlar aynı mantıkla güncellenmezse yeniden çizim «doğru kod ama yanlış çözünürlük» üretir. Yeniden boyutlandırma mantığı sayfası bu geçişi yönetir; performans sayfası yalnız maliyet uyarısı verir: her boyut değişiminde tüm katmanların içeriklerinin geçerli olması gerekir.
Büyük çözünürlük sıçramalarında anında tüm görselleri yeniden ölçeklemek takılmaya yol açabilir; bir karelik degradasyon veya ilerleyen yeniden çizim politikası ürün tercihidir.
Ağır yeniden ölçekleme işlemi çizim döngüsünden çıkarılıp arka planda veya düşük öncelikli kareye yaymak ana iş parçacığını rahatlatır — karmaşık projelerde işçi tuval düşünülür.
Anti-kalıplar: aşırı kare ve unutulan durum
Aşağıdaki alışkanlıklar profil olmadan «neden düşük FPS?» sorusunu zorlaştırır; tarayıcı performans panelinde uygulama veya raster iş parçacığı süresi ani sıçramalar gösterir. Bu sayfanın ölçütü piksel ve bağlam başına maliyettir — taban kavram birinci bölümde özetlenmiştir.
Her öğede bağımsız gölge / süzgeç: Her sprite için
shadowBlur veya ağır
filter açmak, primitif sayısıyla çarpan ek geçiş üretir; mobil
GPU tarafında darboğaz sık görülür. Çözüm: sınırlı «pahalı mod»
geçişi, önceden gölgelenmiş doku kullanımı veya çağrıları gruplamak (
batching ). Pahalı ayarların
kapsamı
dördüncü bölüm ile uyumlu dar
tutulmalıdır.
Kirli bölgeyi küçük hesaplayıp kısmi temizlik: Birleşim kutusu hareketli
nesneyi tam kapsamazsa şeffaf veya eski piksel «hayalet» olarak kalır; bazen tek kare,
bazen birikimli iz. Ya kutuyu güvenli biçimde genişletin ya da
birleştirme mantığını
mergeDirtyRect ile gözden
geçirin; karmaşık sahnede tam silip baştan çizmek (
piksel bütçesi ) bazen daha ucuz olur.
Her varlıkta derin save yığını: İç içe
save /
restore doğru olsa bile CPU tarafında maliyet ve hata riski artar; dönüşümleri
ters sırayla geri almak veya daha sığ sarmalayıcılar kullanmak profili düzleştirir. Çizim
sırasını ürün seviyesinde planlamak,
temizle
ve çiz disipliniyle çakışmadan yürür.
Yüksek DPR ile her kare tam silme: İç tampon alanı
cssWidth * dpr ile büyür; her karede
clearRect(0,0,w,h) piksel sayısını doğrudan çarpar. Hedef oranı düşürmek veya
statik katmanda tam silmeyi azaltmak (
katman stratejisi ) tipik rahatlamadır —
ayrıntı
altıncı bölümde. Gereksiz tam redraw’ları
yeniden çizim bayrağı ile kesmek ayrı
kazançtır.
Bu sayfanın sınırı
Donanıma özel GPU komut kuyruğu analizi ve WebGPU burada işlenmez. Odak: Canvas 2D yeniden çiziminin sezgisel piksel ve durum maliyeti ile ürün içi strateji seçimidir.
- Tam temizlik piksel bütçesiyle gerekçelendirildi mi?
- Kirli birleşim kutusu doğru genişliyor mu?
- Pahalı bağlam ayarları dar kapsamda mı?
- Gereksiz kareler
needsRedrawile eleniyor mu? - DPR ve yeniden boyut senkronu katmanlara uygulandı mı?