Od jakiegoś czasu doświadczyłem przerywanego "jąkania" duszków, które są w ruchu w mojej grze na Androida. Jest to prosta gra 2D OpenGL ES 2.0. (Jest to ciągły problem, który wielokrotnie odwiedzałem).Android: Zrozumienie OnDrawFrame, FPS i VSync (OpenGL ES 2.0)
W mojej pętli gry mam 2 "timery" - taki, który będzie rejestrował liczbę klatek w poprzedniej sekundzie, i drugi, który liczy czas (w milisekundach) od końca aktualnej iteracji OnDrawFrame do początku następnego.
To co znalazłem:
Kiedy nic nie czyniąc, mam 60 kl./s (dla większości), i za każdym razem onDrawFrame nazywa, zgłasza się jako że 16.667ms trwa dłużej. Teraz, jeśli wyrenderuję coś (nie ma znaczenia, czy jest to 1 quad lub 100 quadów, wynik jest taki sam), otrzymuję 60fps (w przeważającej części), ale teraz, tylko około 20% połączeń onDrawFrame raportuje się jako zajmujących więcej czasu niż 16,667ms od ostatniego połączenia.
Naprawdę nie rozumiem, dlaczego tak się dzieje, po pierwsze, dlaczego, kiedy onDrawFrame nic nie robi, nazywa się to "powoli" - i co ważniejsze, dlaczego jakakolwiek rozmowa GL (jeden prosty quad), wciąż czas między wywołaniami onDrawFrame przekracza 16.667 ms (choć znacznie rzadziej).
Powinienem powiedzieć, że kiedy onDrawFrame zgłasza trwa dłużej niż 16.667ms od ostatniej iteracji, prawie zawsze towarzyszy mu spadek FPS (do 58 lub 59), ale nie zawsze, czasami FPS pozostaje stały. I odwrotnie, czasami kiedy FPS spada, naDrawFrame jest wywoływana w ciągu 16.667ms od ostatniej iteracji kończącej.
Więc ......
Próbuję naprawić moją grę pętli i eliminowania tych 'zacina' - kilka innych rzeczy do uwaga:
- Kiedy zrobić metodę profilowanie, pokazuje glSwapBuffers, czasami zajmuje dużo czasu
- Kiedy robię GL Trace, większość scen mówi, że renderuje się w czasie krótszym niż 1 ms, ale czasami ramka nieparzysta zajmuje 3,5-4 ms - tę samą scenę. Nic się nie zmienia oprócz czasu, który zajmuje
- Prawie za każdym razem, gdy klatka jest upuszczana lub na DrawFrame zgłasza duże opóźnienie (lub oba), pojawia się wizualny błąd, ale nie zawsze. Duże wizualne usterki zdają się zbiegać z wieloma "opóźnionymi" wywołaniami w usłudzeDrawFrame i/lub zrzuconymi ramkami.
- Nie sądzę, że jest to problem złożoności sceny z dwóch powodów: 1) nawet jeśli renderuję moją scenę dwukrotnie, to nie sprawia, że problem jest gorszy, nadal w przeważającej części, dostaję 60FPS z okazjonalnym upuść, tak jak poprzednio i 2), nawet jeśli odsłonię scenę, wciąż mam problem.
Oczywiście coś nie rozumiem, więc doceniłbym pchnięcie we właściwym kierunku.
OnDrawFrame
@Override
public void onDrawFrame(GL10 gl) {
startTime = System.nanoTime();
fps++;
totalTime = System.nanoTime() - timeSinceLastCalled;
if (totalTime > 16667000) {
Log.v("Logging","Time between onDrawFrame calls: " + (totalTime /(double)1000000));
}
//Grab time
newTime = System.currentTimeMillis() * 0.001;
frameTime = newTime - currentTime; //Time the last frame took
if (frameTime > 0.25)
frameTime = 0.25;
currentTime = newTime;
accumulator += frameTime;
while (accumulator >= dt){
saveGameState();
updateLogic();
accumulator -= dt;
}
interpolation = (float) (accumulator/dt);
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
render(interpolation);
if (startTime > lastSecond + 1000000000) {
lastSecond = startTime;
Log.v("Logging","fps: "+fps);
fps=0;
}
endTime = startTime;
timeSinceLastCalled = System.nanoTime();
}
Pętla ta gra powyżej jest jednym biorące udział w tej doskonałej article.
Czy usterki pokrywają się ze zdarzeniami zbierania śmieci? –
@ReubenScratton, nie, wszystkie obiekty są tworzone z góry, nie ma przydziałów w pętli ani GC. Wydaje się, że to kwestia czasu z samą pętlą gry (mógłbym się mylić, ale wygląda na to w ten sposób). Dzięki – Zippy
Zakładając, że używasz dedykowanego wątku renderowania, w jaki sposób synchronizujesz stan między nim a głównym wątkiem? (FWIW Nigdy nie używam dedykowanego wątku renderowania i wolę być jednowątkowym, ale nigdy nie napisałem skomplikowanej gry) –