Frame Pacing kitaplığı   Android Game Development Kit'in bir parçasıdır.

Swappy olarak da bilinen Android Frame Pacing kitaplığı, AGDK Kitaplıkları'nın bir parçasıdır. OpenGL ve Vulkan oyunlarının Android'de sorunsuz oluşturma ve doğru kare aralama elde etmesine yardımcı olur. Bu belgede, kare hızının ne olduğu tanımlanır, kare hızının gerekli olduğu durumlar açıklanır ve kitaplığın bu durumları nasıl ele aldığı gösterilir. Doğrudan oyununuzda kare hızını düzenleme özelliğini uygulamaya geçmek istiyorsanız Sonraki adım bölümüne bakın.

Arka plan

Kare hızını düzenleme, bir oyunun mantık ve oluşturma döngüsünün bir işletim sisteminin ekran alt sistemi ve temel ekran donanımıyla senkronize edilmesidir. Android ekran alt sistemi, ekran donanımı güncelleme sırasında yeni bir kareye geçerken oluşabilecek görsel bozulmaları (yırtılma olarak bilinir) önlemek için tasarlanmıştır. Görüntü alt sistemi, bu eserleri önlemek için aşağıdakileri yapar:

  • Geçmiş kareleri dahili olarak arabelleğe alır.
  • Geç gönderilen kareleri algılar
  • Geç kareler algılandığında geçmiş karelerin gösterimini tekrarlar.

Bir oyun, eglSwapBuffers veya vkQueuePresentKHR işlevini çağırarak bir kare için gereken tüm çizim çağrılarını gönderdiğini ekran alt sistemindeki birleştirici olan SurfaceFlinger'a bildirir. SurfaceFlinger, bir mandal kullanarak ekran donanımına bir karenin kullanılabilirliğini bildirir. Ekran donanımı, verilen kareyi gösterir. Ekran donanımı sabit bir hızda (ör. 60 Hz) çalışır ve donanımın yeni bir kareye ihtiyacı olduğunda yeni bir kare yoksa donanım önceki kareyi tekrar gösterir.

Tutarsız kare süreleri genellikle bir oyun oluşturma döngüsü, yerel ekran donanımından farklı bir hızda oluşturma yaptığında ortaya çıkar. 30 FPS'de çalışan bir oyun, 60 FPS'yi doğal olarak destekleyen bir cihazda oluşturulmaya çalışıldığında oyun oluşturma döngüsü, tekrarlanan bir karenin ek 16 milisaniye boyunca ekranda kaldığını fark etmez. Bu bağlantı kesilmesi genellikle kare sürelerinde önemli tutarsızlıklara neden olur. Örneğin: 49 milisaniye, 16 milisaniye, 33 milisaniye. Aşırı karmaşık sahneler, karelerin atlanmasına neden olduğundan bu sorunu daha da kötüleştirir.

En iyi olmayan çözümler

Geçmişte oyunlarda kullanılan aşağıdaki kare hızını düzenleme çözümleri genellikle tutarsız kare sürelerine ve giriş gecikmesinde artışa neden olur.

Kareleri oluşturma API'sinin izin verdiği en kısa sürede gönderme

Bu yaklaşım, oyunu değişken SurfaceFlinger etkinliğine bağlar ve ek bir kare gecikme süresi oluşturur. Görüntüleme işlem hattı, genellikle 2 boyutunda olan ve oyun çerçeveleri çok hızlı sunmaya çalıştığında dolan bir çerçeve sırası içerir. Kuyrukta yer kalmadığında oyun döngüsü (veya en azından oluşturma iş parçacığı) bir OpenGL ya da Vulkan çağrısı tarafından engellenir. Oyun daha sonra ekran donanımının bir kare göstermesini beklemek zorunda kalır ve bu geri basınç iki bileşeni senkronize eder. Bu durum arabellek doldurma veya kuyruk doldurma olarak bilinir. Oluşturucu süreci neler olduğunu anlamadığından kare hızı tutarsızlığı daha da kötüleşir. Oyun, kare öncesinde girişi örneklerse giriş gecikmesi daha da kötüleşir.

Android Choreographer'ı tek başına kullanma

Oyunlar da senkronizasyon için Android Choreographer'ı kullanır. API 16'dan itibaren Java'da ve API 24'ten itibaren C++'da kullanılabilen bu bileşen, ekran alt sistemiyle aynı sıklıkta düzenli tikler sağlar. Bu işaretin gerçek donanım VSYNC'sine göre ne zaman gönderildiğiyle ilgili hâlâ ince ayrıntılar vardır ve bu ofsetler cihaza göre değişir. Uzun karelerde arabelleğe doldurma işlemi yine de gerçekleşebilir.

Frame Pacing kitaplığının avantajları

Frame Pacing kitaplığı, senkronizasyon için Android Choreographer'ı kullanır ve tik teslimatındaki değişkenliği sizin için ele alır. Karelerin doğru zamanda gösterilmesini sağlamak için sunum zaman damgalarını, arabellek doldurmayı önlemek için ise senkronizasyon bariyerlerini kullanır. Kitaplık, NDK Choreographer varsa onu kullanır, yoksa Java Choreographer'a geri döner.

Kitaplık, cihaz tarafından destekleniyorsa birden fazla yenileme hızını işler. Bu sayede oyun, kare sunma konusunda daha fazla esneklik kazanır. Örneğin, 60 Hz yenileme hızının yanı sıra 90 Hz yenileme hızını da destekleyen bir cihazda, saniyede 60 kare üretemeyen bir oyun, akıcı kalmak için 30 FPS yerine 45 FPS'ye düşebilir. Kitaplık, beklenen oyun kare hızını algılar ve kare sunum sürelerini buna göre otomatik olarak ayarlar. Frame Pacing kitaplığı, gereksiz ekran güncellemelerini önlediği için pil ömrünü de uzatır. Örneğin, bir oyun 60 FPS'de oluşturuluyorsa ancak ekran 120 Hz'de güncelleniyorsa ekran her kare için iki kez güncellenir. Frame Pacing kitaplığı, yenileme hızını hedef kare hızına en yakın olan ve cihaz tarafından desteklenen değere ayarlayarak bu durumu önler.

İşleyiş şekli

Aşağıdaki bölümlerde, Frame Pacing kitaplığının doğru kare hızını elde etmek için uzun ve kısa oyun kareleriyle nasıl başa çıktığı gösterilmektedir.

30 Hz'de doğru kare hızı

60 Hz'lik bir cihazda 30 Hz'de oluşturma işlemi yapılırken Android'deki ideal durum Şekil 1'de gösterilmektedir. SurfaceFlinger, varsa yeni grafik arabellekleri kilitler (Şekildeki NB, "arabellek yok" anlamına gelir ve önceki arabellek tekrarlanır).

60 Hz cihazda 30 Hz'de ideal kare hızı

1.şekil 60 Hz cihazda 30 Hz'de ideal kare hızı.

Kısa oyun kareleri takılmaya neden oluyor

Çoğu modern cihazda oyun motorları, karelerin gönderilmesini sağlamak için platform koreografının tikleri iletmesine bağlıdır. Ancak, Şekil 2'de gösterildiği gibi kısa kareler nedeniyle kare hızının düşük olması ihtimali devam etmektedir. Kısa karelerin ardından gelen uzun kareler, oyuncu tarafından titreme olarak algılanır.

Kısa oyun anları

Şekil 2. Kısa oyun karesi C, kare B'nin yalnızca bir kare göstermesine ve ardından birden fazla C karesi göstermesine neden olur.

Frame Pacing kitaplığı, sunum zaman damgalarını kullanarak bu sorunu çözer. Kitaplık, karelerin Şekil 3'te gösterildiği gibi erken sunulmaması için sunum zaman damgası uzantılarını EGL_ANDROID_presentation_time ve VK_GOOGLE_display_timing kullanır.

Sunum zaman damgaları

3.Şekil Daha akıcı bir görüntü için oyun karesi B iki kez gösteriliyor.

Uzun kareler, takılmaya ve gecikmeye neden olur.

Görüntü iş yükü, uygulama iş yükünden daha uzun sürdüğünde sıraya ek kareler eklenir. Bu durum, bir kez daha kekelemeye yol açar ve arabelleğe doldurma nedeniyle fazladan bir kare gecikmeye de neden olabilir (bkz. Şekil 4). Kitaplık, hem titremeyi hem de fazladan gecikme çerçevesini kaldırır.

Uzun oyun kareleri

Şekil 4. Uzun B karesi, A ve B olmak üzere 2 kare için yanlış hız veriyor.

Kitaplık, bekleme sürelerini uygulamaya yerleştirmek için senkronizasyon bariyerlerini (EGL_KHR_fence_sync ve VkFence) kullanarak bu sorunu çözer. Böylece, geri basıncın oluşmasına izin vermek yerine görüntüleme işlem hattının yetişmesine olanak tanır. A karesi hâlâ fazladan bir kare gösteriyor ancak B karesi artık doğru şekilde gösteriliyor (Şekil 5'te gösterildiği gibi).

Uygulama katmanına bekleme süreleri eklendi

5.şekil C ve D çerçeveleri sunulmayı bekliyor.

Desteklenen çalışma modları

Frame Pacing kitaplığını aşağıdaki üç moddan birinde çalışacak şekilde yapılandırabilirsiniz:

  • Otomatik mod kapalı + Pipeline
  • Otomatik mod açık + Ardışık düzen
  • Otomatik mod açık + Otomatik ardışık düzen modu (Ardışık düzen/Ardışık düzen olmayan)

Otomatik mod ve işlem hattı modlarıyla denemeler yapabilirsiniz ancak Swappy'yi başlattıktan sonra bunları devre dışı bırakıp aşağıdakileri ekleyerek başlamanız gerekir:

  swappyAutoSwapInterval(false);
  swappyAutoPipelineMode(false);
  swappyEnableStats(false);
  swappySwapIntervalNS(1000000000L/yourPreferredFrameRateInHz);

Ardışık düzen modu

Kitaplık, motor iş yüklerini koordine etmek için genellikle işlemci ve GPU iş yüklerini VSYNC sınırları arasında ayıran bir işlem hattı modeli kullanır.

Ardışık düzen modu

6.şekil Ardışık düzen modu.

Non-pipeline modu

Genel olarak bu yaklaşım, daha düşük ve daha öngörülebilir giriş ekranı gecikmesiyle sonuçlanır. Kare süresinin çok düşük olduğu oyunlarda hem CPU hem de GPU iş yükleri tek bir takas aralığına sığabilir. Bu durumda, işlem hattı kullanılmayan bir yaklaşım aslında daha düşük giriş ekranı gecikmesi sağlar.

Non-pipeline modu

Şekil 7. Ardışık düzen dışı mod.

Otomatik mod

Çoğu oyun, her karenin sunulma süresi olan takas aralığını (ör.30 Hz için 33, 3 ms) nasıl seçeceğini bilmiyor. Bazı cihazlarda oyun 60 FPS'de işlenebilirken bazılarında daha düşük bir değere düşmesi gerekebilir. Otomatik mod, aşağıdakileri yapmak için CPU ve GPU sürelerini ölçer:

  • Takas aralıklarını otomatik olarak seç: Bazı sahnelerde 30 Hz, bazılarında ise 60 Hz hızında görüntü veren oyunlar, kitaplığın bu aralığı dinamik olarak ayarlamasına izin verebilir.
  • Ultra hızlı kareler için iş hattını devre dışı bırakın: Her durumda optimum giriş ekranı gecikmesi sağlar.

Birden fazla yenileme hızı

Birden fazla yenileme hızını destekleyen cihazlar, sorunsuz görünen bir takas aralığı seçme konusunda daha fazla esneklik sağlar:

  • 60 Hz cihazlarda: 60 FPS / 30 FPS / 20 FPS
  • 60 Hz + 90 Hz cihazlarda: 90 FPS / 60 FPS / 45 FPS / 30 FPS
  • 60 Hz + 90 Hz + 120 Hz cihazlarda: 120 FPS / 90 FPS / 60 FPS / 45 FPS / 40 FPS / 30 FPS

Kitaplık, oyun karelerinin gerçek oluşturma süresine en uygun yenileme hızını seçerek daha iyi bir görsel deneyim sunar.

Birden fazla yenileme hızında kare hızını ayarlama hakkında daha fazla bilgi için Android'de yüksek yenileme hızında oluşturma başlıklı blog yayınını inceleyin.

Kare istatistikleri

Frame Pacing kitaplığı, hata ayıklama ve profil oluşturma amacıyla aşağıdaki istatistikleri sunar:

  • Bir karenin oluşturma işlemi tamamlandıktan sonra birleştirme sırasındaki bekleme süresinin histogramı.
  • İstenen sunum zamanı ile gerçek sunum zamanı arasında geçen ekran yenileme sayısının histogramı.
  • İki ardışık kare arasında geçen ekran yenileme sayısının histogramı.
  • Bu kare için CPU çalışmasının başlangıcı ile mevcut zaman arasında geçen ekran yenileme sayısının histogramı.

Sonraki adım

Android Frame Pacing kitaplığını oyununuza entegre etmek için aşağıdaki kılavuzlardan birine bakın:

Ek kaynaklar