Aktualności Karty graficzne

Przełom w Linux Multi-GPU: Cyberpunk 2077 na eGPU szybszy o ponad 80%

Przełom w Linux Multi-GPU: Cyberpunk 2077 na eGPU szybszy o ponad 80%

Obsługa dodatkowych kart graficznych – a zwłaszcza eGPU (zewnętrznych kart graficznych) – na Linuksie od zawsze pozostawiała wiele do życzenia. Zobaczmy, co dokładnie spowalniało ten proces i w jaki sposób w końcu rozwiązujemy ten problem.

Jak właściwie działa konfiguracja Multi-GPU?

Zanim przejdziemy do systemów z wieloma kartami, przyjrzyjmy się, jak aplikacje wyświetlają obraz na pojedynczym GPU.

W środowisku Wayland do udostępniania obrazu z aplikacji do kompozytora (compositora) wykorzystuje się protokół linux-dmabuf.

  1. Kompozytor informuje aplikację, z którego GPU korzysta, oraz przekazuje listę obsługiwanych formatów DRM[^1] i modyfikatorów formatu[^2].

  2. Aplikacja alokuje bufor dma-buf (direct memory access buffer) dla każdego obrazu na tym samym GPU, którego używa kompozytor.

  3. Aplikacja wysyła kompozytorowi deskryptory plików tych buforów, aby udostępnić obraz.

Rozwiązanie to sprawdza się świetnie, ale tylko w systemach z jedną kartą graficzną. W wersji 5 protokołu linux-dmabuf kompozytor mógł zgłosić jako używalne tylko jedno GPU. Aplikacja mogła co prawda spróbować przekazać bufor z dowolnej innej karty, ale mogło się to skończyć błędem (wymagającym mechanizmów awaryjnych) lub drastycznym spadkiem wydajności.

Dlaczego to działało tak wolno?

Gdy importujesz bufor dma-buf do GPU, kernel stara się być pomocny i automatycznie dba o to, by używana karta miała do niego dostęp. Choć brzmi to dobrze, w praktyce było głównym źródłem problemów z wydajnością.

Scenariusz A: Laptop z iGPU + dGPU (ekran laptopa)

Gdy uruchamiasz grę na dedykowanym GPU (dGPU):

  1. Gra alokuje bufor na dGPU.

  2. Przekazuje go do kompozytora.

  3. Kompozytor importuje bufor do zintegrowanego GPU (iGPU).

Aby krok 3 był możliwy, kernel przenosił[^3] bufor do pamięci RAM komputera. Pamięć systemowa jest jednak drastycznie wolniejsza od pamięci wideo (VRAM), a dGPU musi uzyskiwać do niej dostęp przez magistralę PCIe, co generuje wysokie opóźnienia.

Aby temu zapobiec, sterowniki Vulkan i OpenGL zaczęły porównywać GPU używane przez aplikację z GPU kompozytora. Jeśli się różniły, sterownik sam tworzył kopię w pamięci RAM zamiast dzielić bufor bezpośrednio z VRAM:

  1. Gra alokuje bufor na dGPU.

  2. Sterownik kopiuje bufor do drugiego bufora w pamięci RAM.

  3. Przekazuje kopię do kompozytora.

  4. Kompozytor importuje kopię do iGPU.

Scenariusz B: Laptop z eGPU / dGPU podłączonym do zewnętrznego monitora

Sytuacja robi się jeszcze gorsza, gdy grasz na monitorze zewnętrznym podpiętym bezpośrednio do dedykowanej karty (np. przez HDMI w laptopie):

[ Gra na dGPU ] ──(Kopia 1)──> [ Pamięć RAM ] ──> [ Kompozytor (iGPU) ]
                                                            │
[ Zewnętrzny Monitor ] <──(Kopia 2)── [ Render końcowy na dGPU ] ┘
  1. Gra alokuje bufor na dGPU.

  2. Sterownik kopiuje bufor do pamięci RAM.

  3. Przekazuje kopię do kompozytora.

  4. Kompozytor importuje kopię do iGPU.

  5. Kompozytor wykonuje kompozycję na iGPU.

  6. Kompozytor kopiuje gotowy wynik z powrotem na dGPU, aby wyświetlić go na monitorze.

Obraz z gry jest więc kopiowany do pamięci RAM i z powrotem do VRAM bez żadnego uzasadnionego powodu. Spadek wydajności jest odczuwalny zawsze, ale w przypadku kart zewnętrznych (eGPU) staje się wręcz zabójczy.

Przykład z życia:

W zestawie z laptopem Framework 13, obudową eGPU z kartą RX 5700 XT oraz monitorem 5120x1440 @ 120 Hz podłączonym do eGPU – prosta aplikacja testowa vkcube osiągała zaledwie 55 FPS, ponieważ przepustowość pojedynczego kabla USB-C była całkowicie zapychana przez przesyłanie danych w obu kierunkach naraz.

Rozwiązanie: Wersja 6 protokołu linux-dmabuf

W teorii rozwiązanie jest proste: powstrzymać sterownik przed zbędnym kopiowaniem bufora i przekazać oryginalny bufor z dGPU bezpośrednio do kompozytora.

Właśnie to zaproponowałem w wersji 6 protokołu linux-dmabuf:

  • Kompozytor może zgłaszać listę obsługiwanych GPU (zamiast tylko jednego).

  • Aplikacja może poinformować kompozytor, do którego GPU powinien zaimportować dany bufor.

Wdrożenie w praktyce

Teoria brzmiała prosto, ale realizacja wymagała rozwiązania trzech głównych problemów:

  1. Sterownik nie może wykonywać kopii, dopóki nie są naprawdę konieczne.

  2. Kompozytor musi przejąć wykonywanie kopii, gdy są one niezbędne.

  3. Aby zyskać na wydajności, kompozytor musi pomijać kopiowanie, kiedy tylko jest to możliwe.

Dzięki pomocy Victorii Brekenfeld z System76, protokół zyskał obsługę w bibliotekach Mesa oraz Smithay (używanej przez kompozytor COSMIC).

Dostosowanie KWin (kompozytora KDE) wymagało jednak ponad dwóch lat pracy i napisania od zera wielu mechanizmów:

  • Obsługi wielu GPU i podłączania/odłączania kart w locie (hotplug).

  • Śledzenia, w którym GPU znajduje się dany bufor.

  • Zarządzania resetem GPU podczas operacji kopiowania.

  • Dodania do KWin wsparcia dla Vulkana, aby przesyłanie danych między GPU było tak szybkie, jak to tylko możliwe.

Ostatecznie protokół linux-dmabuf v6 został oficjalnie scalony (merged). Zmiany trafiły już do KWin, niebawem trafią do Mesa, a Nvidia przygotowała odpowiednią obsługę w swoim sterowniku.

Przyrost wydajności w praktyce

Wyniki testów mówią same za siebie:

Test / GraWynik przed (v5)Wynik po (v6)Zysk
vkcube (5120x1440 @ 120Hz)55 FPS120 FPS+118% (pełny odświeżanie)
Cyberpunk 2077 (Preset Low)27 FPS50 FPS+85%

Skok wydajności w Cyberpunku 2077 o ponad 85% pokazuje, jak ogromnym wąskim gardłem była dotychczasowa przepustowość USB-C.

W przypadku klasycznych laptopów z dedykowaną kartą (bez eGPU) zyski będą prawdopodobnie skromniejsze (szacunkowo 5–10%), ze względu na szybsze magistrale wewnętrzne.

dGPU z Mesa main


dGPU z dmabuf v6



Dwa ważne zastrzeżenia (Kiedy to działa?)

Mimo ogromnego sukcesu, obecnie istnieją dwa ograniczenia:

  1. Bezpośrednie skanowanie (Direct Scanout):

    W obecnej implementacji KWin kompozycja zawsze odbywa się na "głównym" GPU. Duże korzyści uzyskasz tylko wtedy, gdy gra korzysta z direct scanout. Przykładowo karta RX 5700 XT wymaga obecnie wyłączonego HDR, braku profilu kolorów oraz wyłączonej funkcji Night Light (część z tych ograniczeń zostanie niedługo zniesiona).

  2. Gry na X11 / Xwayland:

    Największym wyzwaniem pozostają gry uruchamiane przez X11. Z powodu założeń architektonicznych X11, wdrożenie nowego protokołu w Xwayland jest niezwykle trudne. Na ten moment korzyści uzyskają tylko aplikacje i gry działające natywnie na Waylandzie.

    • W przypadku wielu gier natywnych pomaga zmienna środowiskowa SDL_VIDEODRIVER=wayland.

    • W przypadku gier z Windowsa świetnie sprawdzają się widelce Protona z ze sterownikiem Wine Wayland (który świetnie obsługuje już m.in. HDR).

[^1]: Formaty DRM – opisują sposób wykorzystania pamięci w buforze (np. 16-bitowa czerwień, 8-bitowy format RGB z kanałem alpha itp.).

[^2]: Modyfikatory formatu – określają (w uproszczeniu) układ pikseli w pamięci.

[^3]: Przeniesienie bufora – utworzenie kopii w nowym miejscu i usunięcie oryginalnego bufora.

Źródło: Xaver's blog

Zgłoś błąd w tekście

Zauważyłeś literówkę, nieaktualną informację albo problem ze stroną? Daj znać redakcji.

Więcej w kategorii: Aktualności

Komentarze (0)

Brak komentarzy. Bądź pierwszy!

Dodaj komentarz