Mam prostą aplikację testową OpenGL w C, która rysuje różne rzeczy w odpowiedzi na kluczowe dane wejściowe. (Mesa 8.0.4, wypróbowany z Mesa-EGL i GLFW, Ubuntu 12.04LTS na PC z NVIDIA GTX650). Losowania są dość proste / szybkie (obracanie trójkątów). Mój kod testowy nie ogranicza celowo żadnej liczby klatek na sekundę, wygląda to tak:
while (true)
{
draw();
swap_buffers();
}
Zmierzyłem to bardzo dokładnie i stwierdziłem, że czas od jednego eglSwapBuffers()
(lub tego glfwSwapBuffers
samego) połączenia do następnego wynosi ~ 16,6 milisekund. Czas od połączenia do eglSwapBuffers()
momentu tuż przed następnym połączeniem jest tylko trochę mniejszy, mimo że losowanie jest bardzo proste. Czas potrzebny na wywołanie buforów wymiany jest znacznie poniżej 1ms.
Jednak czas od zmiany przez aplikację tego, co rysuje w odpowiedzi na naciśnięcie klawisza, na zmianę, która faktycznie pojawia się na ekranie, wynosi> 150 ms (wartość około 8-9 klatek). Jest to mierzone za pomocą kamery rejestrującej ekran i klawiaturę z prędkością 60 klatek na sekundę.
Dlatego pytania:
Gdzie losowane są buforowane między wezwaniem do zamiany buforów i faktycznie wyświetlane na ekranie? Skąd to opóźnienie? Wygląda na to, że aplikacja cały czas rysuje wiele ramek przed ekranem.
Co może zrobić aplikacja OpenGL, aby spowodować natychmiastowe wyświetlenie ekranu? (tj .: bez buforowania, po prostu blokuj do zakończenia losowania; nie potrzebuję dużej przepustowości, potrzebuję małego opóźnienia)
Co może zrobić aplikacja, aby powyższe natychmiastowe losowanie odbyło się tak szybko, jak to możliwe?
Skąd aplikacja może wiedzieć, co aktualnie jest wyświetlane na ekranie? (Lub jak długo / ile ramek jest bieżące opóźnienie buforowania?)
Odpowiedzi:
Każda funkcja API rysowania wywoływana z CPU zostanie przesłana do bufora pierścienia poleceń GPU, która zostanie wykonana później przez GPU. Oznacza to, że funkcje OpenGL są w większości funkcjami nieblokującymi. Procesor i GPU będą działały równolegle.
Najważniejszą rzeczą do zapamiętania jest to, że twoja aplikacja może być związana z procesorem lub GPU. po wywołaniu glFinish procesor powinien poczekać, aż procesor GPU dokończy wykonywanie poleceń rysowania, jeśli procesor graficzny zajmuje więcej czasu i może / powoduje zatrzymanie procesora, wówczas aplikacja jest związana z GPU. Jeśli procesor graficzny zakończy wykonywanie poleceń rysowania, a proces glFinish trwa zbyt długo, aplikacja jest związana z procesorem.
I zauważ, że istnieje różnica między
glFlush
iglFinish
.glFlush
: wskazuje, że wszystkie polecenia wysłane wcześniej do GL muszą zostać wykonane w określonym czasie.glFinish
: wymusza wykonanie wszystkich poprzednich poleceń GL. Wykończenie nie jest zwracane, dopóki wszystkie efekty wcześniej wydanych poleceń na stanie klienta i serwera GL oraz buforze ramki nie zostaną w pełni zrealizowane. ”glXSwapBuffers wykonuje ukrytą funkcję glFlush przed jej zwróceniem. Kolejne polecenia OpenGL mogą być wydawane natychmiast po wywołaniu glXSwapBuffers, ale nie są wykonywane, dopóki wymiana bufora nie zostanie zakończona.
Rzeczywisty czas ramki najprawdopodobniej zostanie określony na podstawie tego, który z dwóch procesorów / GPU zajmuje więcej czasu na zakończenie swojej pracy.
źródło
both low framerate (exactly same as monitor refresh rate??
nie, chyba że wyraźnie używasz VSync.Technicznie OpenGL nigdy nie aktualizuje ekranu.
Istnieje interfejs API systemu okien, który jest niezależny od GL (np. GLX, WGL, CGL, EGL), który to robi. Zamiana buforów przy użyciu tych interfejsów API zwykle wywołuje niejawnie,
glFlush (...)
ale w niektórych implementacjach (np. Rasterizer GDI w systemie Windows) robi to w pełniglFinish (...)
:* Po lewej stronie znajduje się ścieżka ICD (sprzętowa)
SwapBuffers (...)
. Po prawej stronie ścieżka GDI (oprogramowania).Jeśli masz włączoną funkcję VSYNC i podwójne buforowanie, każde polecenie, które zmodyfikuje bufor tylny przed wystąpieniem oczekującej wymiany, musi zostać zatrzymane do momentu wymiany. Kolejka poleceń ma ograniczoną głębokość, więc to zablokowane polecenie ostatecznie spowoduje zakorkowanie w rurociągu. Może to oznaczać, że zamiast blokować w
SwapBuffers (...)
twojej aplikacji, faktycznie blokuje jakieś niepowiązane polecenie GL, dopóki VBLANK się nie zmieni. To, co tak naprawdę sprowadza się do tego, to ile buforów tylnych masz w swoim łańcuchu wymiany.Tak długo, jak wszystkie tylne bufory są pełne gotowych ramek, które mają zostać jeszcze przeniesione na przód, bufory wymiany pośrednio powodują blokowanie. Niestety, nie ma sposobu, aby jawnie kontrolować liczbę buforów tylnych używanych przez większość interfejsów API systemu okien GL (oprócz 0 jedno-buforowych lub 1 podwójnie buforowanych). Sterownik może swobodnie korzystać z 2 tylnych buforów, jeśli chce (potrójne buforowanie), ale nie można tego żądać na poziomie aplikacji przy użyciu czegoś takiego jak GLX lub WGL.
źródło
glFinish (...)
natychmiast po zamianie buforów. Spowoduje to wyczyszczenie kolejki poleceń, ale oznacza również, że procesor graficzny i procesor zostaną zsynchronizowane (co nie jest dobre, jeśli chcesz, aby procesor graficzny cały czas działał).Zakładam, że znasz ten eksperyment ?
Zasadniczo John Carmack robił coś podobnego, rejestrując ekran i wysyłając na ekran piksele synchronizacji. Odkrył, że znaczna część opóźnień pochodzi z ekranu. Innymi czynnikami były opóźnienie wejściowe z klawiatury, sterowników wideo i / lub kurs wykonania samego programu.
źródło