RazzorFlame Temat założony przez niniejszego użytkownika |
Dziwne działanie funkcji Sleep. » 2014-10-03 18:08:37 Albo ja mam jakieś omamy, albo nie umiem tak prostych rzeczy albo windows postanowił sobie porobić ze mnie jaja. Czy na prawdę jest jakiś powód, z którego ten kod ma prawo nie działać? v3de::Timer tim; tim.play(); double secCount = 0; double frameTime = 0; const double sixtyFPSFrameTime = 16; int frames = 0; while( vWindow->isReachable() ) { vWindow->pollEvent(); v3de::Message ms = vWindow->getWindowEvent(); if( ms.type == v3de::Message::Unknown ) { vWindow->clearWindow( D3DXCOLOR( 0, 255, 0, 0.0f ) ); scene.drawSorted( vWindow ); vWindow->drawScene(); } if( ms.type == v3de::Message::Closed ) { break; } else if( ms.type == v3de::Message::KeyDown ) { } secCount +=( tim.getTime() /( double )( 1000000 ) ); frameTime =( tim.getTime() /( double )( 1000 ) ); if( frameTime < sixtyFPSFrameTime ) { double timeWaste = sixtyFPSFrameTime - frameTime; Sleep( timeWaste ); } frames++; if( secCount >= 1 ) { secCount -= 1; cout << "FPS: " << frames << endl; frames = 0; } tim.restart(); }
Tak wykonana pętla powinna ograniczyć FPSy do ok. 60 a zawiesza mi na jakiś czas aplikacje, a "cout << "FPS: "<<frames<<endl;" wykonuje się co pare sekund. Timer.hpp #ifndef V3DETIMER_HPP_INCLUDED #define V3DETIMER_HPP_INCLUDED
#include "v3deMain.hpp" #include <ctime>
namespace v3de { typedef unsigned long long Microseconds; class Timer { Microseconds startTime; Microseconds idleTime; Microseconds currentTime; Microseconds stopTime; char state; void update(); public: Timer(); void play(); void stop(); void pause(); Microseconds getTime(); Microseconds restart(); double getSeconds(); static Microseconds clocksToMilliseconds( clock_t ); static Microseconds getCurrentTime(); static double getFrequency(); enum { Stopped = 0, Paused = 1, Playing }; }; }
#endif
Timer.cpp #include "v3deTimer.hpp"
namespace v3de { double Timer::getFrequency() { static LARGE_INTEGER li; static bool once = false; static double freq = 0.0; if( !once ) { if( !QueryPerformanceFrequency( & li ) ) cout << "QueryPerformanceFrequency failed!\n"; freq = double( li.QuadPart ); } return freq; } Microseconds Timer::getCurrentTime() { LARGE_INTEGER li; QueryPerformanceCounter( & li ); return 1000000 * li.QuadPart / getFrequency(); } Timer::Timer() { startTime = Timer::getCurrentTime(); stopTime = Timer::getCurrentTime(); idleTime = 0; currentTime = 0; state = Timer::Playing; } void Timer::update() { if( state == Timer::Playing ) { currentTime = Timer::getCurrentTime() - startTime - idleTime; } else { idleTime += Timer::getCurrentTime() - stopTime; stopTime = Timer::getCurrentTime(); } } void Timer::stop() { update(); state = Timer::Stopped; restart(); } void Timer::pause() { state = Timer::Paused; stopTime = Timer::getCurrentTime(); } void Timer::play() { if( state != Timer::Playing ) { if( state == Timer::Stopped ) restart(); else update(); state = Timer::Playing; } } Microseconds Timer::restart() { update(); Microseconds c = currentTime; startTime = Timer::getCurrentTime(); stopTime = Timer::getCurrentTime(); idleTime = 0; currentTime = 0; return c; } Microseconds Timer::getTime() { if( state == Stopped ) return 0; if( state == Paused ) { return currentTime; } update(); return currentTime; } double Timer::getSeconds() { double a = 1000000; return( double )( getTime() / a ); } }
Plys pomuszcie! <--- z tą pisownią to żarcik :) Dodam że timeWaste wynosi ok. 15,5ms. Kiedy wyświetlam w każdym obrocie pętli tą zmienną to program się nie tnie ale też nie ogranicza fps do 60 (FPS wtedy wynosi przeciętnie 500-600). |
|
Monika90 |
» 2014-10-03 20:20:52 Czy w funkcji getCurrentTime nie dochodzi czasem do przepełnienia przy mnożeniu przez milion? Wtedy zachowanie jest niezdefiniowane, wynikiem może być liczba ujemna. Może najpierw podziel przez getFrequency() a dopero potem mnóż. A tutaj double timeWaste = sixtyFPSFrameTime - frameTime;
jeżeli się zdarzy że frameTime jest większe niż 16, to timeWaste będzie ujemne, przekazanie ujemnej wartości typu double do funkcji Sleep to też niezdefiniowane zachowanie. |
|
RazzorFlame Temat założony przez niniejszego użytkownika |
» 2014-10-03 20:33:31 timeWaste jest zmienną lokalną tworzoną tylko wtedy gdy frameTime < 16. Edit: Masz na myśli takie coś? ( time.QuadPart / frequency.QuadPart ) * 1000000 Też nie działa. Pewnie coś z obliczeniami w programie jest źle, raczej nie z klasą Timer. Sprawdziłem właśnie czy działa kiedy użyje SFML'owego Clocka. Działa tak samo. Prosze oto lekko zmodyfikowany kod: v3de::Clock tim; long double secCount = 0; long double frameTime = 0; const long double sixtyFPSFrameTime = 0.016; int frames = 0; while( vWindow->isReachable() ) { vWindow->pollEvent(); v3de::Message ms = vWindow->getWindowEvent(); if( ms.type == v3de::Message::Closed ) { break; } else if( ms.type == v3de::Message::KeyDown ) { if( ms.key == v3de::Key::Escape ) { vWindow->destroy(); break; } else if( ms.key == v3de::Key::Num1 ) { obj.setRasterizer( obj.getRasterizer() == "Solid" ? "Wireframe" : "Solid" ); } else if( ms.key == v3de::Key::Num2 ) { obj.setTexture( obj.getTexturePath() == "cubetex.png" ? "cubetex2.png" : "cubetex.png" ); } } else if( ms.type == v3de::Message::Unknown ) { calcPos = obj.getPosition(); calcRot = obj.getRotation(); gcos = cos( -( calcRot.y ) / 180 * XM_PI ); gsin = sin( -( calcRot.y ) / 180 * XM_PI ); calcPos += v3de::uVector3 < float >( gcos * 6, 4, gsin * 6 ); vWindow->dxGetCamera()->setPosition( calcPos ); vWindow->dxGetCamera()->setTarget( obj.getPosition() + v3de::uVector3 < float >( - gcos * 5, 0, - gsin * 5 ) ); vWindow->dxGetCamera()->update(); kmgr.checkKeys(); if( kmgr.isKeyDown( v3de::Key::Right ) ) { obj.setRotation( obj.getRotation() + v3de::uVector3 < float >( 0, 0.15, 0 ) ); } if( kmgr.isKeyDown( v3de::Key::Left ) ) { obj.setRotation( obj.getRotation() - v3de::uVector3 < float >( 0, 0.15, 0 ) ); } obj.setPosition( obj.getPosition() + v3de::uVector3 < float >( - gcos * velocity, 0, - gsin * velocity ) ); if( kmgr.isKeyDown( v3de::Key::Up ) ) { velocity += velStep * tim.getElapsedTime().asSeconds(); } else if( kmgr.isKeyDown( v3de::Key::Down ) ) { velocity -= velStep * tim.getElapsedTime().asSeconds(); } else { if( velocity > 0 ) { velocity -= velDelayStep * tim.getElapsedTime().asSeconds(); if( velocity < 0 ) velocity = 0; } else if( velocity < 0 ) { velocity += velDelayStep * tim.getElapsedTime().asSeconds(); if( velocity > 0 ) velocity = 0; } } secCount += tim.getElapsedTime().asSeconds(); if( secCount >= 1 ) { cout << "SecCount:" << secCount << endl; secCount -= 1; cout << "FPS: " << frames << endl; frames = 0; } else frames++; frameTime = tim.getElapsedTime().asSeconds(); if( frameTime < sixtyFPSFrameTime ) { double timeWaste = sixtyFPSFrameTime - frameTime; Sleep( timeWaste * 1000 ); } tim.restart(); vWindow->clearWindow( D3DXCOLOR( 0, 255, 0, 0.0f ) ); scene.drawSorted( vWindow ); vWindow->drawScene(); } }
Edit: Dodam że te wszystkie obliczenia związane z kamerą wcześniej też były ale teraz ich nie zakomentowałem. Edit: Te Sleep to jakaś podróba. Jeżeli to zakomentuje to wtedy wszystko działa ale nie ogranicza fps. A może nie można tak często wywoływać sleep... Nie wiem. |
|
oputyk |
» 2014-10-03 20:52:05 A spróbuj użyć sf::sleep. Dodatkowo poleciłbym sprawdzić jak wygląda argument wprowadzany do Sleep. Jak będzie za duży, to sprawdzić, która z instrukcji źle modyfikuje zmienną. |
|
RazzorFlame Temat założony przez niniejszego użytkownika |
» 2014-10-03 20:59:27 Mówiłem, timeWaste wynosi ok. 14,5ms. A oto jak wygląda w SFML funkcja sf::sleep (dla systemu Windows)... TADAM: namespace sf { void sleep( Time duration ) { if( duration >= Time::Zero ) priv::sleepImpl( duration ); } }
A tutaj priv::sleepImpl: namespace sf { namespace priv { void sleepImpl( Time time ) { ::Sleep( time.asMilliseconds() ); } } }
|
|
pekfos |
» 2014-10-03 21:30:15 Nie wystarczy synchronizacja pionowa? Sleep() to bardzo słabe rozwiązanie. |
|
RazzorFlame Temat założony przez niniejszego użytkownika |
» 2014-10-03 21:40:39 Hmm, a dzięki VSync zmniejsze zużycie procka? Jak na razie to pobiera mi go 25% i to prawie cały czas (przecież nie ograniczam klatek, mam 4 rdzenie procesora. 100%/4 = 25%). |
|
« 1 » |