Tworząc renderer, który obsługuje wiele interfejsów API grafiki, zwykle chcesz wyodrębnić kod w jakiejś bibliotece niskiego poziomu, która jest powiązana z niektórymi interfejsami API grafiki, takimi jak OpenGL, Vulkan, D3D11 i tak dalej;
Działają one bardzo odmiennie, dlatego tworzenie dobrego ogólnego API staje się niezbędne; Czytałem, że zwykle chciałbyś użyć „zaplecza”, który implementuje podstawową funkcjonalność dla każdego interfejsu API, który chcesz obsługiwać, oraz „interfejsu”, który jest używany przez programistę do rysowania rzeczy na ekran.
Skąd mam wiedzieć, czy robię zbyt ciasną abstrakcję?
graphics-programming
Gabriele Vierti
źródło
źródło
Odpowiedzi:
Przede wszystkim zastanów się, czy naprawdę warto obsługiwać więcej niż jeden graficzny interfejs API. Samo użycie OpenGL obejmie większość platform i będzie „wystarczająco dobre” dla wszystkich oprócz najbardziej ambitnych graficznie projektów. O ile nie pracujesz dla bardzo dużego studia gier, które może pozwolić sobie na zatopienie kilku tysięcy osobogodzin we wdrażaniu i testowaniu wielu backendów renderujących i chyba że są jakieś funkcje specyficzne dla DirectX lub Vulcan, które naprawdę chcesz się pochwalić, zwykle nie jest to warte kłopotu . Zwłaszcza biorąc pod uwagę, że możesz zaoszczędzić dużo pracy, używając warstwy abstrakcji stworzonej przez kogoś innego (biblioteka innej firmy lub silnik gry).
Ale załóżmy, że już oceniłeś swoje opcje i doszedłeś do wniosku, że jest to opłacalne i warte czasu, aby rzucić własne.
Zatem głównym sędzią architektury oprogramowania twojej warstwy abstrakcji są twoi programiści.
Jeśli tak, to ci się udało.
źródło
Zacznij od określenia, czego potrzebujesz w części „otoki” interfejsu API. Zasadniczo jest to bardzo, bardzo proste: potrzebujesz podstawowych zasobów (buforów, shaderów, tekstur, stanu potoku) i sposobu na wykorzystanie tych zasobów do zbudowania ramki przez przesłanie niektórych wywołań losowania.
Staraj się trzymać logikę wysokiego poziomu z dala od opakowania API. Jeśli zaimplementujesz sprytną technikę przerywania sceny w tej części interfejsu API, teraz masz problem z powieleniem tej logiki we wszystkich implementacjach zaplecza. To dużo dodatkowego wysiłku, więc zachowaj prostotę. Zarządzanie scenami powinno być częścią wyższego poziomu interfejsu API, który używa opakowania, a nie częścią samego opakowania.
Wybierz cele, które będziesz wspierać i zrozum je. Trudno jest napisać przyzwoite opakowanie dla „wszystkiego” i prawdopodobnie nie musisz (prawdopodobnie nie musisz pisać ani jednego opakowania, jak zauważono w odpowiedzi Filipa ). Prawie niemożliwe jest napisanie przyzwoitego opakowania, jeśli nie znasz już interfejsów API, które zamierzasz zawinąć.
Regularnie oceniaj stan swojego interfejsu API. Zasadniczo powinien mieć mniejszą powierzchnię niż leżące u podstaw owinięte API; jeśli odkryjesz, że tworzysz typy opakowań jeden do jednego dla każdej struktury D3D lub każdego wywołania funkcji OpenGL, prawdopodobnie zboczysz z kursu.
Spójrz na to, co już minęło. Sokol i BGFX to interfejsy API, które zapewniają poziomy agnostycyzmu, które mogą być przydatne i stosunkowo łatwe do zrozumienia (szczególnie te pierwsze).
źródło
Kolejną kwestią, o której jeszcze nie wspomniano, którą należy wziąć pod uwagę, są cele dotyczące wydajności. Jeśli Twoim celem jest posiadanie biblioteki graficznej, która zapewni dobrą wydajność dzięki taniej platformie sprzętowej, ale będzie również użyteczna na różnych platformach, które są znacznie bardziej wydajne, ale używają innego interfejsu API, warto zaprojektować interfejs API wszelkie abstrakty są używane natywnie na platformie, na której wydajność jest problemem. Nawet jeśli powoduje to obniżenie prędkości o 50% na bardziej wydajnych platformach, może być tego warte, jeśli pozwala na zwiększenie prędkości o 20% na platformie, na której wydajność ma największe znaczenie.
źródło