Uzun zamandır üzerinde çalıştığım ve istemcinin bel kemiğini oluşturan grafik motoru modernizasyonunu tamamladım. Bu yazıda yüzeysel geçmek yerine arkada dönen mimariyi, karşılaştığım teknik darboğazları ve çözümleri detaylıca anlatmak istedim.
1. Eski Miras Mimari ve Karşılaşılan Sorunlar
Metin2'nin orijinal istemcisi bildiğiniz gibi DirectX 8-9 FFP (Fixed Function Pipeline) mimarisine göbekten bağlıydı. Kod tabanında CStateManager, küresel LPDIRECT3DDEVICE9 işaretçileri ve D3DFVF bayrakları motorun neredeyse her yerine (GameLib, EterLib, UserInterface, EffectLib) kılcal damar gibi yayılmıştı. Bu durum üç büyük soruna yol açıyordu
- Modern işletim sistemlerinde ve yeni nesil ekran kartlarında (özellikle Intel Arc ve yeni AMD/Nvidia sürücülerinde) DX9 emülasyon katmanının getirdiği FPS dalgalanmaları ve mikro takılmalar (stuttering).
- Sabit fonksiyonlu render durumlarının (FFP) modern GPU gölgelendiricileriyle (programmable shaders) esnek çalışamaması.
- Kodun tek bir grafik API'sine kilitli kalması yüzünden farklı arka uçlara (DX11, Vulkan vb.) geçişin imkansız hale gelmesi.
2. Neler Yaptım? (Mimari ve Teknik Detaylar)
A) Özel RHI (Render Hardware Interface) Katmanı
İlk iş olarak motoru doğrudan DirectX çağrıları yapmaktan kurtardım. Donanım ve grafik kütüphanesi arasında soyut bir katman (IRHIDevice, IRHITexture, IRHIBuffer, IRHIShader, RHIFactory) kurdum. Bütün render boru hattını C++23 standartlarında, RAII disipliniyle ve sıfır-tahsis (zero-allocation) döngüsüyle yeniden yapılandırdım. Artık oyun motoru arkada hangi API'nin çalıştığını bilmiyor; yalnızca RHI arayüzüyle konuşuyor.
B) DirectX 11 (HLSL Shader Model 5.0) Boru Hattı
DirectX 11 backend'ini sıfırdan inşa ettim:
- DXGI SwapChain yönetimi, modern render target yapıları ve dinamik vertex/index buffer havuzları kuruldu.
- Karakterler, harita zeminleri (terrain), su efektleri, ağaçlar (SpeedTree) ve parçacık sistemleri (effects) HLSL SM 5.0 gölgelendiricilerine uyarlandı.
- Aynı zamanda eski sistemlerle tam uyumluluğu korumak adına klasik DirectX 9 boru hattını da HLSL SM 3.0 seviyesinde RHI'a bağladım. İki API arasında sıfır regresyon ve tam görsel sadakat sağlandı.
C) Oyun İçi Dinamik API Geçişi ve Çoklu Dil Desteği
Kullanıcının karmaşık ayarlarla uğraşmadan grafik motorunu değiştirebilmesi için Sistem Seçenekleri menüsüne doğrudan motor seçim arayüzü entegre ettim. Ayar metin2.cfg içine kaydediliyor ve 8 farklı dilde (tr, en, de, hu, it, pl, pt, ro) standart olarak yerelleştirildi.
D) Draw Call Optimizasyonu ve Sınırsız 500+ FPS
DirectX 11'i ilk ayağa kaldırdığımda kare hızının monitörün tazeleme hızına kilitlendiğini ve CPU tarafında gereksiz bir sürücü yükü oluştuğunu tespit ettim. Bunu çözmek için şu müdahaleleri yaptım:
- SwapChain Present Desync: DXGI başlatma sırasındaki sabit VSync bayrağını kaldırıp istemci ayarlarına dinamik olarak bağladım. VSync kapalıyken Present(0, 0) çalıştırılarak DX11 tarafındaki FPS kilidi tamamen kırıldı.
- Input Layout Önbellekleme: DX11'de her draw call çağrısında FNV-1a ile bytecode hash'i üretilip unordered_map üzerinden layout aranıyordu. Bunu dirty check ve m_pBoundInputLayout kontrolüne alarak kare başına binlerce kez çalışan anlamsız hash hesaplamalarını sıfıra indirdim.
- Constant Buffer ve Doku Slot Önbelleklemesi: Her çizimde yinelenen VSSetConstantBuffers/PSSetConstantBuffers COM çağrılarını temizledim. SetTexture fonksiyonuna 8 slotluk doku durum kontrolü ekleyerek aynı dokunun alt alta defalarca GPU'ya bağlanmasını (bind overhead) engelledim.
- Debug Layer İzolasyonu: Release derlemelerinde aktif kalan D3D11_CREATE_DEVICE_DEBUG bayrağını kapatarak Microsoft Debug Layer'ın binlerce draw call üzerinde yarattığı CPU doğrulama gecikmesini yok ettim.
Sonuç olarak 360Hz monitörümde DirectX 11 modunda VSync kapalıyken 500+ FPS değerlerini yakaladım
E) Geliştirici ve Teşhis Araçları
Geliştirme aşamasında render analizlerini profesyonelce yapabilmek için:
- RenderDoc Entegrasyonu: F12 tuşuna basıldığında çalışan kareyi doğrudan GPU seviyesinde yakalayan kancayı (API hook) D3D11 moduna entegre ettim.
- Dear ImGui Paneli: Oyun içi kamera, buffer, shader sabitleri ve anlık kare istatistiklerini izleyebileceğim geliştirici arayüzünü motora gömdüm.
3. Sırada Ne Var?
RHI soyutlaması sayesinde motor artık tamamen platform ve API bağımsız hale geldi. Bir sonraki durağım; oyunu yerel olarak Linux, Steam Deck ve Android mobil platformlarına taşıyabilmek adına saf bir Vulkan backend'i yazmak olacak. Ama biraz windowstan koparmak istiyorum bağımlılıklarım oldukça az o yüzden hızlı olur ne zaman yaparım bilmiyorum..