Dawno nie pisałem nic tutaj na wykopie, ponieważ mocno pochłąnął mnie rozwój silnika gier na Vulkanie i od ostatniego wpisu w kwietniu siedziałem długie godziny po pracy, aby stworzyć podwaliny pod renderer i udało mi się! Chciałbym podzielić się z wami moją historią na temat tworzenia silnika opartego o Vulkan API. W tym wpisie będzie trochę anegdot, trochę żali i trochę kwestii technicznych. Mam nadzieję, że każdy znajdzie coś dla siebie, także weźcie kompot i lecimy z tematem jeden po drugim!
Linux – obecny na pokładzie
Zacznijmy od pozytywnych aspektów, czyli wsparcie dla wielu systemów operacyjnych. Nie jest zaskoczeniem, że mój silnik działa na Windowsie, ale działa on też na Linuxie. Moim zdaniem to fajna opcja, bo skoro silnik jest tworzony na wieloplatformowy API to głupio by było nie wykorzystać tej możliwości i nie dodać wsparcia dla Linuxa.
Warto od razu napisać, że pisanie na wiele platform nie jest takie proste. Zacznijmy może od C++, który ma swój standard, co jest super, ale ten standard jest dość… luźny. Efektem tego jest to, że kompilator Microsoftu jest bardzo dopracowany i pobłażliwy, co prowadzi do tego, że kod pisany pod niego często nie kompiluje się na Linuksowych kompilatorach, ponieważ wiele elementów jest w nim zaimplementowane w inny sposób. Braki #include są czymś standardowym, ale zdarzają się też dziwne zachowania niektórych elementów, a obsługa czasu przyprawiła mnie o kilka siwych włosów, bo na Linuxie chrono działał delikanie inaczej. Poza tym, już kiedyś pisałem, że znalazłem błąd w jednym z kompilatorów do C++, także nie ma sensu się o tym rozpisywać jeszcze raz. No, ale to głupoty i do przeskoczenia. Możecie zapytać, czy przez takie „pierdoły” nie powstają duże gry AAA na Linuxa? Nie, nie, nie. To są pierdoły, a najlepsze dopiero przed nami!
Sterowniki od Nvidii na Linuxie są… zabugowane. Matko… jak one są zabugowane. Może ja nie umiem obsłużyć Linuxa, albo jestem głupi, ale mam non-stop problemy ze sterownikami do RTX 3080 na moim Linux Mint. W teorii wszystko działa poprawnie, ale w praktyce jak włączę warstwę walidacyjną w moim silniku to lecą tam takie głupoty… . i co gorsza nie są one prawdą. Pewnie da się to naprawić i już czuję, że w komentarzu mi to ktoś napisze, ale jednak Linux to nie jest system typu Plug&Play i dopóki takim się nie stanie to nigdy nie będę moim zdaniem powstawać na niego gry AAA, w takiej ilości, jak powstają na Windowsa. Zresztą, jak można dostarczyć sterowniki, które są tak problematyczne? Nawiasem mówiąc, podobno AMD nie ma takich problemów na Linuxie, ale jednak Nvidia dość mocno dominuje rynek niezintegrowanych układów graficznych.
„Wincyj generatoruf!”
Pisanie powtarzalnego kodu ręcznie jest moim zdaniem złe z wielu powodów. Po pierwsze odciąga nas od designu całej wielkiej machiny jaką jest oprogramowanie, które tworzymy, a po drugie łatwo jest o głupi błąd, który potem możemy rozwiązywać długimi godzinami. Po co sobie robić problemy? Jeżeli można coś zautomatyować to jak najbardziej warto.
Pierwszy geneartor, który chciałbym krótko opisać to kompilator shaderów. Jest to dość prosta sprawa i działa on w taki sposób, że wyszukuje nieskompilowane shadery napisane w języku GLSL, a następnie kompiluje je do formatu SPIR-V. Całość jest uruchomiana automatycznie dzięki podpięciu jej pod CMake. Tutaj możecie zobaczyć ten skrypcik.
Drugi generator jest trochę bardziej zaawansowany i zanim do jego samego przejdę, to muszę kilka zdań opisać o problemie, który chciałem rozwiązać, a może nie być oczywisty dla kogoś kto nie pisze w Vulkanie. Wierzchołki, z których składa się każdy model na scenie, są przekazywane do GPU, ale w celu odpowiedniego ich przyporządkowania, potrzebny jest VkVertexInputAttributeDescription. Ta śmieszna struktura zawiera w sobie informacje na temat bindingu każdego z pól struktury naszego wierzchołka (rozmiar, przesunięcie, miejsce bindingu, pozycja). Pisanie tego ręcznie moim zdaniem również mija się z celem, bo łatwo zapomnieć, aby zaktualizować listę z tymi deskryptorami. Dlatego właśnie stworzyłem kolejny skrypt, który przechodzi po klasach oznaczonych odpowiednim makrem, a następnie na podstawie pól w tej strukturze generuje te deskryptory dla danej struktury. Jest to niesamowicie pomocne i zapobiega nerwom. Link do skryptu jest tutaj.
VULKAN
No i na koniec perła w koronie, czyli Vulkan. Po piewsze: O MATKO ILE KODU (╥﹏╥). Vulkan wymaga napisania ogromnej ilości kodu, a do tego ten kod jest skomplikowany. Starałem się ukryć te kawałki kodu jak najbardziej się da w moich klasach, w których robię co mogę, żeby to API w C nie przeszkadzało nam, a do tego jak najbardziej uprościć obsługę tego renderera, jednocześnie nie psując wydajności. Brzmi jak trudne zadanie i takie jest. Z tego powodu sporo czasu zeszło na prace koncepcyjne i opracowywanie własnego API, które ukryje tyle, ile się da. Na przykład, Graphics Pipeline został przykryty pięknym Budowniczym (wzorcem projektowym), w taki sposób, że tworzenie Pipeline nie jest już taką katorgą, bo możemy wywołać odpowiednie funkcje, które ustawią wewnętrznie odpowiednio stany, a następnie możemy zbudować sobie Pipeline. Jest to łatwe proste i przyjemne. Świetnym przykładem przykrycia API jest też Vertex Buffer, który to za pomocą wywołania funkcji UploadData() pozwala przesłać w prosty sposób dane z RAM do VRAMu z użyciem Staging Buffera, a my jedyne co widzimy to prosta funkcja.
Podsumowanie
Mam nadzieję, że ktoś dotarł ze mną do końca. Jeżeli tak, to jest mi bardzo miło. Bardziej dogłębny artykuł znajdziecie na Linkedin, ale jest on dostępny tylko w języku angielskim. Gdyby, ktoś chciałby docenić projekt to możecie zostawić tutaj na wykopie plusika. W razie pytań, zapraszam do komentowania, a ja postaram się odpowiedzieć na wszystkie pytania. Jeżeli napisałem jakieś głupoty w tym wpisie, to również zapraszam do napisania poniżej, bo mogłem coś źle opisać lub po prostu się pomylić, a przecież jestem tylko człowiekiem.
Jednocześnie cieszę się, że mogę wrzucać takie wpisy na wykop, ponieważ chciałbym trochę odczarować wykop, że jest to tylko straszne miejsce do trollingu, śmiesznych obrazków oraz polityki. Mam nadzieję, że tak chociaż w małym procencie stanie się też trochę miejscem z fajnymi programistycznymi artykułami ( ͡º ͜ʖ͡º).
—
Artykuł na Linkedin
Kod źródłowy
Wersja wykonywalna
—
#programowanie #gamedev #gry #vulkan #grafikakomputerowa #clusek #linux #windows