Czy modyfikowanie tekstury (malowanie na niej) jest uważane za „zmianę stanu”?


11

Konwencja w grafice jest taka, że ​​przeprowadzanie mniejszej liczby zmian stanu jest lepsze niż wykonywanie większej liczby zmian stanu (przełączanie shaderów, buforów wiązania, wiązanie tekstur itp.). W przypadku tekstur szybsze jest renderowanie wielu wielokątów za pomocą jednego atlasu (do renderowania duszków / tekstu) niż indywidualne wiązanie nowej tekstury dla każdego wielokąta.

Czy to prawda, jeśli ciągle maluję teksturę poprzez glTexSubImage2D? Mam strumień danych przychodzących (przez sieć), który jest przetwarzany, a następnie malowany do tekstury po jednym wierszu na raz. Dane są prezentowane wizualnie w nieskończonym przewijaniu.

Czy lepiej byłoby namalować jedną teksturę renderowaną na jednym dużym prostokącie (przewijanie pomalowanych danych do widoku)? Chodzi o to, żebym miał jedną (lub dwie) tekstury związane w danym momencie, a ja po prostu nadal malowałem.

Czy powinienem malować wiele małych prostokątów (odsłaniając prostokąt dopiero po zakończeniu malowania)? Zakładam, że powiązałbym jedną teksturę na prostokąt.

Odpowiedzi:


11

Aktualizacja obszaru pamięci w urządzeniu graficznym (tekstury, bufora itp.) Nie jest tym samym, co zmiana stanu renderowania.

To, co powoduje, że zmiana stanu renderowania jest kosztowna, to ilość pracy, którą sterownik musi wykonać, aby sprawdzić poprawność nowych stanów i zmienić kolejność potoku. Najprawdopodobniej spowoduje to również pewną synchronizację między procesorem a urządzeniem graficznym. Jednak ilość danych przesyłanych między urządzeniami powinna być mała dla zmiany stanu (prawdopodobnie tylko kilka poleceń).

Z drugiej strony w przypadku aktualizacji tekstury / bufora główny koszt leży w samym transferze danych. Teoretycznie, chyba że odczytujesz dane tekstur z powrotem do CPU po aktualizacji, synchronizacja lub wstrzymanie potoku nie powinno być. Należy jednak wziąć pod uwagę inny aspekt: ​​narzut API. Nawet jeśli ilość danych wysyłanych do urządzenia graficznego jest niewielka, jeśli robisz to wystarczająco często, ostatecznie koszt komunikacji ze sterownikiem / urządzeniem stanie się większy niż koszt transferu danych. To kolejny powód, dla którego wsadowanie jest tak ważne przy optymalizacji renderera.

Tak więc w twoim przypadku najlepszym podejściem, jak mi się wydaje, byłoby zachowanie kopii tekstury pamięci systemowej, którą aktualizujesz, gdy pojawią się nowe dane. Ustaw brudną flagę i skonsoliduj jak najwięcej aktualizacji w jedną glTexSubImagedla całej tekstury (lub jej dużej sekwencyjnej części). Możesz także grać z obiektami Pixel Buffer Objects i próbować wykonywać asynchroniczny transfer danych, aby maksymalnie ograniczyć utknięcia w rurociągu. Jeśli możesz wdrożyć jakiś rodzaj podwójnego buforowania, możesz napisać do jednej kopii tekstury podczas renderowania drugiej. Ten samouczekbada ten scenariusz. To moje intuicyjne podejście, staram się zmniejszyć liczbę wywołań interfejsu API i „grupować” aktualizacje tekstur. Biorąc to pod uwagę, jest to bardzo spekulacyjne i trzeba by profilować i porównywać to z innymi podejściami, takimi jak robienie kilku małych aktualizacji, aby na pewno wiedzieć, która z nich jest najbardziej wydajna w twoim przypadku użycia.

Na marginesie, ta prezentacja firmy NVidia jest również istotna i zapewnia wiele dobrych informacji: Podejście do zerowego obciążenia sterownika w OpenGL .


5
Nie wiem na pewno, ale na pewno podejrzewałbym, że glTexSubImage na teksturze, która została renderowana w ostatniej lub dwóch klatkach, zablokuje potok, ponieważ sterowniki PC często próbują buforować klatkę lub dwie i nie są prawdopodobne chcieć robić kopie całych tekstur z powodu drobnej aktualizacji. Spodziewałbym się więc podwójnego lub potrójnego buforowania tekstur (lub obiektów bufora pikseli), aby uzyskać maksymalną wydajność.
John Calsbeek,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.