GPU Pipeline &
Rendering Optimization
Aygün ÖZGÜR
2025
00 İçindekiler
-
01
Giriş & Profesyonel Yaklaşım
-
02
GPU Temelleri
-
03
Unity Rendering Sistemi
-
04
Culling Sistemleri
-
05
Shader & Material Optimizasyonu
-
06
Proje Örnekleri
-
07
Pratik Araçlar
-
08
Checklist & Özet
01 Bu Workshop Neden Gerekli?
Oyun geliştirme sürecinde performans optimizasyonu genellikle "sonra bakarız" yaklaşımıyla ertelenir.
Ancak temel rendering kavramlarını anlamadan yapılan işler, projenin ilerleyen aşamalarında ciddi performans sorunlarına yol açar.
Workshop'un Amacı:
- GPU'nun nasıl çalıştığını temel seviyede anlamak
- Unity'nin rendering pipeline'ını kavramak
- Shader ve material optimizasyonunun "neden" önemli olduğunu öğrenmek
- Projede tespit edilen sorunları incelemek
01 Önemli Not: Profesyonel Yaklaşım
Bu dokümandaki teknik tespitler kişisel eleştiri değildir.
Burada belirtilen sorunlar ve öneriler, yapılan işin daha iyi olması için sunulan teknik geri bildirimlerdir.
Kimse kötü iş yapmıyor.
Sorun genellikle iletişimsiz ve izinsiz yapılan değişikliklerden kaynaklanıyor.
Bu yüzden:
- Yeni shader eklemeden önce Lead Developer ile görüşün
- Mevcut sistemleri anlamadan değişiklik yapmayın
- Teknik kararları birlikte alalım
02 CPU vs GPU - Mimari Farklar
| Özellik |
CPU |
GPU |
| Core Sayısı |
4-16 (güçlü) |
1000+ (basit) |
| Görev Tipi |
Seri işlemler |
Paralel işlemler |
| Karar Verme |
Mükemmel |
Zayıf |
| Aynı İşi Tekrarlama |
Orta |
Mükemmel |
Analoji
CPU bir profesör gibidir - karmaşık problemleri tek başına çözebilir.
GPU ise bir fabrika hattıdır - aynı basit işlemi binlerce kez paralel yapabilir.
02 GPU'nun Gücünü Doğru Kullanmak
Kritik Bilgi
GPU'ya "karar vermeyi gerektiren" işler yüklerseniz (çok sayıda farklı shader, farklı state'ler), GPU'nun paralel işlem gücünü boşa harcarsınız.
Kötü Kullanım
- Her obje için farklı shader
- Sürekli state değişimi
- GPU "karar veriyor"
İyi Kullanım
- Aynı shader, farklı material
- Minimal state değişimi
- GPU "aynı işi tekrarlıyor"
Altın Kural: GPU en verimli şekilde "aynı işi binlerce kez" yaptığında çalışır.
02 Rendering Pipeline Aşamaları
┌─────────────────┐
│ Application │ ← CPU: Oyun mantığı
│ Stage │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Geometry Stage │ ← GPU: Vertex işleme
│ (Vertex Shader) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Rasterization │ ← Triangle → Pixel
│ │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Fragment Stage │ ← GPU: Pixel renklendirme
│ (Pixel Shader) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Output Merger │ ← Depth test, blending
│ │
└─────────────────┘
Aşamalar
- Application: CPU tarafında oyun mantığı
- Vertex Shader: Her köşe noktası için çalışır
- Rasterization: 3D → 2D dönüşümü
- Fragment Shader: Her pixel için çalışır
- Output Merger: Final görüntü
02 Vertex Shader vs Fragment Shader
Vertex Shader
3D modelin her köşe noktası için çalışır.
- Pozisyon hesaplama
- Normal transform
- UV koordinat manipülasyonu
10,000
vertex = 10K çalışma
Fragment Shader
Ekrandaki her pixel için çalışır.
- Texture sampling
- Lighting hesaplama
- Final renk belirleme
Kritik Nokta
Büyük objeler için Fragment Shader maliyeti çok yüksek olabilir. Ekranda kapladığı alana bağlıdır!
02 Rasterization Nedir?
Rasterization, 3D triangle'ları 2D pixel grid'ine dönüştürme işlemidir.
Triangle (3 vertex) Pixels
* ░░░█░░░
/ \ → ░░███░░
/ \ ░█████░
*─────* ███████
Bu aşamada:
- Hangi pixel'lerin triangle içinde olduğu hesaplanır
- Her pixel için interpolated değerler (UV, normal, color) üretilir
- Fragment Shader'a input hazırlanır
03 Draw Call Nedir?
Draw Call, CPU'nun GPU'ya "şu mesh'i, şu material ile çiz" demesidir.
CPU GPU
│ │
├─► "Mesh A + Material X" ──► Çiz
├─► "Mesh B + Material Y" ──► Çiz
├─► "Mesh C + Material X" ──► Çiz
└─► ... ...
Her Draw Call maliyetlidir çünkü:
- CPU-GPU senkronizasyonu gerektirir
- GPU state'i değişebilir
- Driver overhead ekler
03 GPU State Change ve Maliyeti
GPU, render state'ini değiştirdiğinde performans kaybı olur.
| State Değişikliği |
Maliyet |
Açıklama |
| Shader değişimi |
ÇOK YÜKSEK |
GPU pipeline yeniden konfigüre |
| Texture değişimi |
YÜKSEK |
Farklı texture bind etme |
| Material property |
ORTA |
Aynı shader, farklı parametreler |
| Mesh değişimi |
DÜŞÜK |
Vertex buffer swap |
Kritik Bilgi
10 farklı shader kullanmak, 1 shader + 10 material kullanmaktan çok daha maliyetlidir!
03 Batching Türleri
Batching, birden fazla Draw Call'u tek bir Draw Call'a birleştirme işlemidir.
Static Batching
- Statik objeler tek mesh'e birleştirilir
- Static flag + aynı material gerekli
- Runtime CPU maliyeti yok
- Memory artışı dezavantajı
Dynamic Batching
- Küçük mesh'ler runtime'da birleşir
- <300 vertex, aynı material
- CPU overhead var
SRP Batcher (URP/HDRP)
- Aynı shader variant gruplandırılır
- Farklı material property'leri olabilir
- En modern yaklaşım
Static Batching:
Mesh A + Mat X ─┐
Mesh B + Mat X ─┼─► Tek Draw Call
Mesh C + Mat X ─┘
SRP Batcher:
Mesh A + Mat X (shader Y) ─┐
Mesh B + Mat Z (shader Y) ─┼─► GPU State korunur
Mesh C + Mat W (shader Y) ─┘
03 Static Batching Dikkat!
Static Batching ve Culling Sorunu
Static Batching kullanıldığında, birleştirilen tüm objeler tek bir bounding box altında gruplanır.
Bu durum:
- Frustum Culling'i bozar: Kamera sadece bir objeyi görse bile, batch'teki tüm objeler render edilir
- Occlusion Culling'i bozar: Bir duvar arkasındaki objeler cull edilmeyebilir
Çözüm
Static Batching'i dikkatli kullanın. Çok geniş alana yayılmış objeler için ayrı batch'ler oluşturun veya SRP Batcher tercih edin.
04 Culling Sistemleri
Frustum Culling
Kameranın görüş alanı dışındaki objeleri render etmeme işlemi.
Kamera Görüş Alanı
╱─────────╲
╱ ╲
╱ [Render] ╲
╱ ╲
╱ ╲
[X] [X]
Cull Cull
OTOMATİK Unity'de otomatik çalışır.
Occlusion Culling
Başka objeler tarafından kapatılan objeleri render etmeme.
Kamera ──► [Duvar] [Arkadaki]
Render Cull ✓
MANUEL Ayar gerektirir:
- Window → Rendering → Occlusion Culling
- Occluder/Occludee işaretleme
- Bake işlemi
04 Ne Zaman Culling Çalışmaz?
| Durum |
Neden |
Çözüm |
| Vertex displacement |
Bounding box güncellenmez |
Custom bounds ayarla |
| Çok büyük bounding box |
Obje her zaman "görünür" |
Mesh'i parçala |
| LOD Group yanlış ayar |
Culling distance hatalı |
LOD seviyelerini kontrol et |
| Static Batching |
Tek bounding box |
Batch gruplarını dikkatli oluştur |
04 Mesh Vertex Sorunları
Mesh'lerin ek noktalarında veya weld edilen kısımlarda ufak boşluklar kalabilir:
Kötü Weld Örneği:
Mesh A Mesh B
│ │
└──┐ ┌────┘
│ ◄── │ Boşluk (gap)
┌──┘ └────┐
│ │
Sorunlar:
- Shadow Leak: Işık bu boşluklardan sızar
- Occlusion Culling Hatası: Arkadaki objeler görünür kalır
- Light Probe Sızıntısı: Hatalı aydınlatma
Çözüm
3D yazılımda vertex'leri merge edin. Wireframe mode'da kontrol edin. Tolerance: 0.001 unit
05 Shader Variant Nedir?
Shader Variant, aynı shader'ın farklı keyword kombinasyonlarıyla derlenmiş versiyonlarıdır.
#pragma multi_compile _ FOG_ON
#pragma multi_compile _ SHADOWS_ON
Bu shader için 4 variant derlenir:
- (hiçbiri)
- FOG_ON
- SHADOWS_ON
- FOG_ON + SHADOWS_ON
N keyword = 2N variant
05 Boolean ve Factorial Growth
Her boolean/toggle 2x variant demektir:
| Boolean Sayısı |
Hesaplama |
Variant Sayısı |
| 1 boolean |
2¹ |
2 |
| 5 boolean |
2⁵ |
32 |
| 10 boolean |
2¹⁰ |
1,024 |
| 20 boolean |
2²⁰ |
1,048,576 |
| 50 boolean |
2⁵⁰ |
1+ Katrilyon! |
Kritik Uyarı
Shader'a her eklediğiniz [Toggle] property, variant sayısını KATLAR. 10 toggle = 1024 variant = build süresinde patlama!
05 multi_compile vs shader_feature
| Direktif |
Derleme |
Kullanım |
multi_compile |
HEPSİ derlenir |
Runtime'da değişecek global keyword'ler |
shader_feature |
Sadece kullanılanlar |
Material'e bağlı, strip edilir |
shader_feature_local |
En verimli |
Sadece o material için |
Kötü
#pragma multi_compile _ EFFECT_A
#pragma multi_compile _ EFFECT_B
#pragma multi_compile _ EFFECT_C
// Hepsi build'e dahil!
İyi
#pragma shader_feature_local _ EFFECT_A
#pragma shader_feature_local _ EFFECT_B
#pragma shader_feature_local _ EFFECT_C
// Sadece kullanılanlar!
05 Shared Material Avantajları
Ayrı Material'ler
Building_01 → M_Building_01 → Shader X
Building_02 → M_Building_02 → Shader X
Building_03 → M_Building_03 → Shader X
= 3 Draw Call, batch break
Shared Material
Building_01 ─┐
Building_02 ─┼─► M_Buildings → Shader X
Building_03 ─┘
= 1 Draw Call (batched)
Shared Material Gereksinimleri:
- Aynı texture atlas kullanımı
- MaterialPropertyBlock ile instance-specific değerler
- Aynı shader variant
06 Kritik Bağlam: Entegrasyon Projesi
ÖNEMLİ
Bu proje (Integration Project) ana oyundan ayrı bir entegrasyon projesidir. Ana oyuna dahil edildiğinde shader sayıları birleşecek.
| Proje |
Shader Sayısı |
| Bu proje (Integration) |
~60 |
| Ana proje |
~300-600 (5-10x) |
| Birleştirildiğinde |
~360-660+ |
"Az shader var" diyip geçmeyin.
Her eklenen shader, final build'de katlanarak etki eder.
06 Mevcut Durum Analizi
Kritik Shader Sorunları:
| Shader |
Sorun |
Kritiklik |
| Splatmap.shader |
600+ shader_feature |
YÜKSEK |
| Grunge.shader |
50+ multi_compile |
YÜKSEK |
| Weather System |
40+ farklı shader |
ORTA |
06 Örnek: Grunge Shader
[Toggle] _Grunge_ON
[KeywordEnum(R,G,B)] _GrungeChannel
+ 50 adet multi_compile direktifi
Hesaplama:
2 × 3 × 250 = ?
6,755,399,441,055,744
Altı katrilyon yedi yüz elli beş trilyon üç yüz doksan dokuz milyar
dört yüz kırk bir milyon elli beş bin yedi yüz kırk dört variant
Pratik olarak SONSUZ variant!
Bu shader build patlamasına ve memory bloat'a neden olur. multi_compile → shader_feature_local'e dönüştürülmeli.
06 Shader'ın Gerçek Maliyeti
Ana projede yapılan URP/Lit shader stripping işlemi sonuçları:
8 GB
Stripping Öncesi RAM
1.5 GB
Stripping Sonrası RAM
18 saat
Stripping Öncesi Build
15 dk
Stripping Sonrası Build
%98.6
Build Süresi Azalması
Bu stripping manuel yapıldı:
- Tüm variant'lar tek tek not edildi
- Sahnelerde gezilerek kullanılan variant'lar tespit edildi
- Farklı kalite ayarlarına göre test edildi
Her eklediğiniz shader, development'a ekstra iş demek.
07 Pratik Araçlar
Frame Debugger
Window → Analysis → Frame Debugger
- Her Draw Call'un sırası
- Hangi shader/material kullanılıyor
- Batch'lerin neden bozulduğu
- Render state değişiklikleri
Shader Variant Sayısını Görme
- Shader asset'ini seç
- Inspector → "Compile and show code"
- "Show" → variant listesi
Profiler
Window → Analysis → Profiler → GPU
- SetPass Calls: Shader değişim sayısı
- Draw Calls: Toplam çizim komutları
- Batches: Birleştirilmiş Draw Call
- Triangles: Çizilen geometri
Build Log
Console'da "Compiling shader" satırlarını arayın.
08 Checklist
Shader Yazarken
- multi_compile yerine shader_feature_local
- Boolean sayısını minimize et
- KeywordEnum seçeneklerini sınırla
- SRP Batcher uyumluluğunu kontrol et
Material Oluştururken
- Mümkünse mevcut material'i paylaş
- Texture atlas kullan
- MaterialPropertyBlock düşün
Sahne Optimizasyonu
- Static objeleri işaretle
- LOD Group kullan
- Occlusion Culling bake et
- Cast Shadows gereksizse kapat
Build Öncesi
- Shader variant count kontrol et
- Graphics Settings stripping ayarları
- Kullanılmayan shader'ları kaldır
08 Özet
| Konu |
Anahtar Nokta |
| GPU Çalışma Prensibi |
Paralel işlem, state değişimi maliyetli |
| Draw Call |
CPU→GPU komut maliyeti, batching ile azalt |
| Shader Variant |
Boolean sayısı = 2N variant, dikkatli ol |
| Material Sharing |
Aynı material = batch, farklı = ayrı Draw Call |
| Culling |
Frustum otomatik, Occlusion manuel setup |
Altın Kural
GPU'ya mümkün olduğunca az "karar" verdirin.
Aynı shader, aynı material, aynı state = maksimum performans.
Sorular?
Teknik sorularınız için iletişime geçebilirsiniz.
Aygün ÖZGÜR