Interfejs Vulkan różni się od wcześniejszych interfejsów API grafiki tym, że w przypadku aplikacji sterowniki nie wykonują niektórych optymalizacji, np. ponownego użycia potoku. Zamiast tego aplikacje korzystające z interfejsu Vulkan muszą wdrożyć takie optymalizacje samodzielnie. Jeśli tak nie jest, mogą działać gorzej niż aplikacje z algorytmem OpenGL ES.
Gdy aplikacje samodzielnie wdrażają te optymalizacje, mogą zrobić to skuteczniej niż sterownik, ponieważ mają dostęp do bardziej szczegółowych informacji dotyczących danego przypadku użycia. W efekcie umiejętna optymalizacja aplikacji, która używa interfejsu Vulkan, może przynieść wzrost wydajności niż w przypadku korzystania z platformy OpenGL ES.
Na tej stronie opisujemy kilka optymalizacji, które możesz wdrożyć w swojej aplikacji na Androida, aby poprawić wydajność dzięki interfejsowi Vulkan.
Akceleracja sprzętowa
Większość urządzeń
obsługuje interfejs Vulkan 1.1 dzięki akceleracji sprzętowej, a mały podzbiór obsługuje ją za pomocą emulacji programowej. Aplikacje mogą wykrywać programowe urządzenie Vulkan za pomocą funkcji vkGetPhysicalDeviceProperties
i sprawdzając pole deviceType
zwróconej struktury.
Parametr SwiftShader i inne implementacje oparte na procesorze mają wartość VK_PHYSICAL_DEVICE_TYPE_CPU
.
Aplikacje mogą sprawdzać zgodność z SwiftShader, sprawdzając pola vendorID
i deviceID
tej samej struktury pod kątem wartości specyficznych dla SwiftShader.
W aplikacjach o kluczowym znaczeniu dla wydajności nie należy używać emulowanych programowo implementacji interfejsu Vulkan i zamiast tego przełączaj się na OpenGL ES.
Zastosuj obrót wyświetlacza podczas renderowania
Jeśli orientacja aplikacji skierowanej w górę nie odpowiada orientacji wyświetlacza urządzenia, kompozytor obraca obrazy łańcucha wymiany aplikacji tak, aby były zgodne. Obraca się podczas wyświetlania obrazów, co powoduje większe zużycie energii – czasem nawet znacznie większe niż w przypadku braku obrócenia.
Z kolei obracanie obrazów łańcucha wymiany przy ich generowaniu powoduje niewielkie (o ile w ogóle) dodatkowe zużycie energii. Pole VkSurfaceCapabilitiesKHR::currentTransform
wskazuje rotację, którą kompozytor stosuje do okna. Gdy aplikacja zastosuje tę rotację podczas renderowania, korzysta z pola VkSwapchainCreateInfoKHR::preTransform
, aby zgłosić, że rotacja się zakończyła.
Minimalizuj liczbę przebiegów renderowania na klatkę
W większości architektur GPU na urządzeniach mobilnych rozpoczęcie i zakończenie renderowania jest kosztowne. Twoja aplikacja może zwiększyć wydajność, organizując operacje renderowania w jak najmniejszej liczbie przebiegów renderowania.
Różne operacje wczytywania załączników i przechowywania załączników mają różne poziomy wydajności. Jeśli na przykład nie musisz zachowywać zawartości załącznika, możesz użyć znacznie szybszej metody VK_ATTACHMENT_LOAD_OP_CLEAR
lub VK_ATTACHMENT_LOAD_OP_DONT_CARE
zamiast VK_ATTACHMENT_LOAD_OP_LOAD
. I podobnie, jeśli nie musisz zapisywać w pamięci ostatecznej wartości załącznika, aby użyć ich później, możesz użyć VK_ATTACHMENT_STORE_OP_DONT_CARE
, aby uzyskać znacznie lepszą wydajność niż VK_ATTACHMENT_STORE_OP_STORE
.
W większości kart renderowania aplikacja nie musi wczytywać ani przechowywać załącznika głębi/szablonu. W takich przypadkach można uniknąć przydzielania fizycznej pamięci do załączników, używając flagi VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
podczas tworzenia obrazu załącznika. Ten fragment ma te same zalety co funkcja glFramebufferDiscard
w trybie OpenGL ES.
Wybierz odpowiednie typy pamięci
Podczas przydzielania pamięci urządzenia aplikacje muszą wybrać typ pamięci. Typ pamięci określa, jak aplikacja może korzystać z pamięci, a także opisuje właściwości buforowania i spójności pamięci. W zależności od urządzenia dostępne są różne typy pamięci, różne typy pamięci mają różną charakterystykę wydajności.
Aplikacja może używać prostego algorytmu do wyboru najlepszego typu pamięci do danego zastosowania. Ten algorytm wybiera w tablicy VkPhysicalDeviceMemoryProperties::memoryTypes
pierwszy typ pamięci, który spełnia 2 kryteria: typ pamięci musi być dozwolony dla bufora lub obrazu i musi mieć minimalne właściwości wymagane przez aplikację.
Systemy mobilne zwykle nie mają osobnych stert pamięci fizycznej dla procesora i GPU. W takich systemach funkcja VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
nie jest tak istotna jak w przypadku systemów z oddzielnymi procesorami graficznymi i własną dedykowaną pamięcią. Aplikacja nie powinna zakładać, że ta właściwość jest wymagana.
Grupuj zestawy deskryptorów według częstotliwości
Jeśli masz powiązania zasobów, które zmieniają się z różną częstotliwością, używaj wielu zbiorów deskryptorów na potok, zamiast ponownie łączyć wszystkie zasoby przy każdym pobieraniu. Na przykład możesz mieć jeden zestaw deskryptorów do powiązań poszczególnych scen, drugi zestaw do wiązań dla poszczególnych materiałów i trzeci na potrzeby powiązań poszczególnych instancji siatki.
W przypadku zmian o największej częstotliwości, np. zmian wprowadzanych przy każdym wywołaniu rysowania, używaj stałych stałych.