2013-03-30 19 views
5

W jaki sposób można załadować tekstury asynchronicznie podczas działania aplikacji 3D? Rozumiem, że konteksty OpenGL nie są bezpieczne dla wątków i że powinienem je rozdzielić na różne wątki.Udogodnienia dotyczące asynchronicznego ładowania tekstur

Ale moim głównym problemem jest wybieranie odpowiedniego wielowątkowego obiektu/struktury, aby faktycznie zaimplementować to z Windows i C++. Słyszałem wiele o C++ 11, w tym obsługę wątków w standardowym lbrararium, ale czy ktoś mógłby po prostu ustawić podstawowe kroki?

Jaki byłby najbezpieczniejszy sposób na zrobienie tego? I jak można zaktualizować stan innego kontekstu, w którym rejestruje zmiany dokonane w innym wątku? Podejrzewam, że glFlush i glBind*?

+0

W rzeczywistości konteksty OpenGL i OpenGL ** są ** bezpieczne dla wątków. Możesz po prostu włączyć jeden kontekst w więcej niż jednym wątku naraz. – datenwolf

Odpowiedz

5

Najbardziej czasochłonnym elementem ładowania tekstur jest zazwyczaj dostęp do dysku i dowolna konwersja formatu, które są niezależne od OpenGL i dzięki temu mogą bezpiecznie odbywać się w innym wątku. Po wczytaniu tekstury do pamięci i w żądanym formacie, rzeczywista kopia do bufora OpenGL jest dość szybka.

Wchodzenie w szczegóły programowania z gwintami jest całkowicie zbyt skomplikowane dla tej odpowiedzi, ale jest tu sporo dokumentacji i po kliknięciu w głowę jest to dość łatwe (jak wskaźniki i pamięć).

Ogólna koncepcja polega na utworzeniu listy obiektów posiadających tekstury (zawierających, powiedzmy, plik/nazwę, początkowo zerowy bufor i flagę loading-complete) i przekazanie go do wątku ładowania po utworzeniu . Wątek ładowania następnie przechodzi przez listę, otwiera każdy plik, ładuje go do pamięci i dołącza bufor do pozycji listy, a następnie ustawia załadowaną flagę i może zwiększać licznik. Główny wątek pobiera nowo załadowaną teksturę, kopiuje ją do tekstury OpenGL i zwiększa pasek postępu lub jakikolwiek jest twój wskaźnik ładowania. Gdy wszystkie tekstury na liście mają bufory i są oznaczane jako załadowane, praca innego wątku jest ukończona i można ją zatrzymać (lub pozostawić przy życiu, aby załadować przyszłe tekstury).

Główną zaletą tego modelu jest fakt, że nie trzeba udostępniać rzeczywistego kontekstu graficznego. W interfejsach API, które mogą być bezpieczne dla wątków (DirectX), jest za to kara za wydajność, a OpenGL wymaga przyzwoitego trochę pracy z twojej strony, aby mieć wiele kontekstów lub upewnić się, że poprawnie je udostępniasz. Ciężkie podnoszenie podczas ładowania tekstur to zazwyczaj odczyt plików i sprawdzanie parametrów, chyba że dokonasz konwersji lub rotacji, co może przydać się nawet przy dostępie do dysku. Rzeczywista kopia w pamięci wideo jest wysoce zoptymalizowana i prawdopodobnie nie będzie wąskim gardłem (jeśli się o to martwisz, spróbuj profilowania w narzędziu rozpoznającym koszt połączenia GPU i zobacz). Żadna z tych prac nie zależy bezpośrednio od OpenGL, więc możesz go odepchnąć na inny wątek z bardzo małym zmartwieniem.

Jeśli korzystasz z systemu Windows, istnieją wbudowane funkcje wątków, które można wykorzystać, działając w oparciu o prosty model wywołania zwrotnego (podaj funkcję i początkowe parametry, w tym przypadku listę tekstur i utwórz interfejs API połączenie). Nie jestem osobiście zaznajomiony z obsługą wątków C++ 11 lub jak działa w Visual Studio, jeśli w ogóle, więc musisz to sprawdzić.

+0

Dobra odpowiedź. Tak, C++ 11 'std :: thread' działa na MSVC++. Jego użycie jest * bardzo podobne * do 'boost :: thread'. –

0

Odpowiedź @ssube jest poprawna w odniesieniu do rozkładu złożoności zadania, ale zakłada, że ​​"OpenGL wymaga przyzwoitego trochę pracy z twojej strony, aby mieć wiele kontekstów lub upewnić się, że udostępniasz je poprawnie", a ja nie zgadzać się.

Łatwym rozwiązaniem jest utworzenie główny kontekst (na rysunku) oraz kontekst wtórnego (dla tekstury załadunku), na początku programu, na przykład:

m_hRCDrawing = wglCreateContext(m_hDC); 
m_hRCSecondary = wglCreateContext(m_hDC); 

A potem dzielenie danych pomiędzy m_hRCSecondary i m_hRCDrawing kontekstach mogą być wykonane z:

wglShareLists(m_hRCSecondary, m_hRCDrawing); 

Wreszcie, kiedy masz zamiar czytać fakturę od „tekstury loading” wątek, który nie ma żadnego kontekstu GL, można po prostu zadzwonić:

wglMakeCurrent(m_hDC, m_hRCSecondary); 

po którym wszystkie zasoby załadowane w tym wątku są współużytkowane przez kontekst wątku rysunku.

Dostępne jest nieco bardziej szczegółowe wyjaśnienie: here.