Autor Wątek: Czy poniższa próba optymalizacji wywołania DirectD3D11* jest sensowna?  (Przeczytany 1620 razy)

Offline kubera

  • Użytkownik
    • Prywatna strona

# Sierpień 18, 2016, 20:04:10
Chodzi mi o wypisanego w kodzie if-a:

void CMesh::Render() noexcept
{
if (LastVertices != m_pVertices.Get())
{
const UINT Offsets = 0;
assert(m_pIndices);
assert(m_pVertices);
DXUTGetD3D11DeviceContext1()->IASetVertexBuffers(0, 1, m_pVertices.GetAddressOf(), &VertexSizeInBytes, &Offsets);
DXUTGetD3D11DeviceContext1()->IASetIndexBuffer(m_pIndices.Get(), DXGI_FORMAT_R32_UINT, 0);
LastVertices = m_pVertices.Get();
}
DXUTGetD3D11DeviceContext1()->DrawIndexed(IndicesSizeInBytes / sizeof(UINT), 0, 0);
}

Może niższe warstwy (DirectX, sterownik) mają z definicji przechowywać redundantne wywołania w cache bez kontaktowania się z GPU?
Posiadam instancje renderowane.

Z góry dziękuję za odpowiedź.

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline ArekBal

  • Użytkownik

  • +1
# Sierpień 18, 2016, 20:48:30
Jest zbędna, wprowadzająca w błąd i w niewłaściwym miejscu.

Ten problem renderowania przeróżnych meshy i struktur powinieneś i pewnie tak się stanie od niechcenia, rozwiązać systemowo.

To wygląda tak, jak byś chciał programistę chronić przed samym sobą.

Jeśli mogę coś podpowiedzieć...
Metoda Render na obiekcie CMesh nie jest takim systemowym rozwiązaniem, bo pozwalasz obiektowi trzymającemu dane na renderowanie siebie samego. Koniec końców będziesz chciał zebrać te dane do kupy(meshe, particle, materiały), poukładać wg. określonego "widzimisie" i wyrenderować w określony sposób.

Jak już systemowo się za to zabierzesz, to zobaczysz że takie pseudo - optymalizacje w normalnym systemie powinny być zastosowane systemowo... np. poprzez trzymanie pogrupowanej i posortowanej kolekcji gotowej do renderowania. Jak dorzucasz do sceny element, to jego składowe w odpowiednich strukturach powinny się porozkładać same. Jak przesuwasz, powiększasz element... scena, czy whatever dostosowuje struktury...

Offline kubera

  • Użytkownik
    • Prywatna strona

# Sierpień 18, 2016, 22:22:07
Masz rację, if jest trochę anachronizmem programowania imperatywnego i rzeczywiście można lepiej.
Pytanie jednak pozostaje, która warstwa:
3. Aplikacja
2. Direct3D
1. Sterownik grafiki
powinna zauważyć, że właśnie wystąpił duplikat zamiast zmiany stanu?
Czy może jest to wydajnościowo bez znaczenia?


Dzięki serdeczne.
W.



Offline ArekBal

  • Użytkownik

  • +1
# Sierpień 19, 2016, 11:01:07
Aplikacja, ale nie "powinna zauważyć", powinna doprowadzać do niej, gdy to tylko możliwe i grupować wywołania.

Offline kubera

  • Użytkownik
    • Prywatna strona

# Sierpień 19, 2016, 11:11:43
OKI, to dzięki.

Offline Reg

  • Administrator
    • Adam Sawicki - Home Page

  • +1
# Sierpień 19, 2016, 14:14:00
Moim zdaniem taka optymalizacja może mieć sens. Już pomijając pytanie, co się dzieje dokładnie w sterowniku graficznym i czy sterownik sam śledzi, jaki ostatni VB i IB był ustawiony i ewentualne nadmiarowe wywołania jego ustawienia zignoruje, to samo wywołanie metody z interfejsu Direct3D (który jest przecież w technologii COM, a więc interfejsy, funkcje wirtualne i te sprawy...) też ileśtam czasu kosztuje (chociaż niedużo), więc jeżeli można go łatwo uniknąć, to czemu nie.

Offline Armageddon

  • Użytkownik

  • +1
# Sierpień 19, 2016, 15:09:35
Tak jak Reg, taka optymalizacja ma sens i potrafi całkiem sporo zmniejszyć narzut sterownika/direct'a na CPU. Wszelkie odwołania do API czy to DirectX czy OpenGL mają swój koszt(często duży) dlatego przed wywołaniem metod Draw*(), warto sprawdzić czy nie próbujemy bindować shadera/textury/buffera poraz drugi. No i warto wtedy posortować swoje drawcalle po materiale tak aby zmniejszyć jak najbardziej liczbę wywołan do API.

Offline kubera

  • Użytkownik
    • Prywatna strona

# Sierpień 19, 2016, 15:57:01
Z tym sortowaniem, to Panowie macie rację, ale 10 lat temu, sortowało się do bufora głębi :), żeby nie zapisywać tego samego pixela wiele razy :), ciekawe co będzie za 10 lat...

Dziękuję serd. za uwagi.
Tej wiedzy mi wystarczy i można zamknąć temat.

Offline DanielMz25

  • Użytkownik

  • +3
# Sierpień 20, 2016, 08:38:13
Moim, skromnym zresztą zdaniem. Prawda jest gdzieś pomiędzy. Ta optymalizacja może mieć sens. Ale przy odpowiednim skonstruowaniu silnika jest całkiem zbędna... Co nie znaczy że całkiem zła, bo przecież pojedynczy if przy zmianie tekstury czy shadera to narzut praktycznie zerowy (chyba  że zmieniasz miliard razy na klatkę, ale to znaczy że wszystko musisz napisać od nowa), a zabezpiecza nas przed dwukrotnym wyborem tych samych komponentów.
A co do sortowania do głębi. To dalej się takie rzeczy robi. Typ optymalizacji jest zależny od typu gry i modelu oświetlenia. Trochę inaczej będziesz optymalizował forward, inaczej deferred i inaczej forward+. Inna będzie optymalizacja przy RTSie, który ma w miarę statyczną kamerę, inaczej RPG z bardzo dynamiczną pracą kamery, a jeszcze inaczej symulator wyścigów czy zręcznościówkę w której programista decyduje skąd patrzy kamera. Dlatego prawie wszystkie poważne produkcje śmigają na własnych, albo nawet jeśli gotowych, to całkowicie przerobionych silnikach.
Co nie zmienia faktu, że sortowanie po materiałach/teksturach/buforach prawie zawsze daje kopa i jest raczej niezbędne. W deferredzie sortujemy po materiałach -> odległości. W forward+ mamy Z pre pass i sortowanie po materiałach. W forwardzie, różnie ale prawie zawsze po materiałach.
Jeśli chcesz zrobić super silnik, to lepiej zamiast tego ifa, dać sobie jakieś:
#ifdef debug
if (LastVertices == m_pVertices.Get())
   std::cout<<"Ponowne wybranie bufora verteksów!!!!"<<std::endl;
#endif
Albo coś w ten deseń, tylko lepsze(bo to to to syf, ale chodzi o ideę a nie sam kod) i pisz tak żeby samo zmieniało komponenty tak często jak trzeba i ani razu więcej.
« Ostatnia zmiana: Sierpień 20, 2016, 09:25:53 wysłana przez DanielMz25 »

Offline kubera

  • Użytkownik
    • Prywatna strona

# Sierpień 20, 2016, 09:57:48
Dzięki za odpowiedź.