Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Dziwne działanie funkcji Sleep.

Ostatnio zmodyfikowano 2014-10-03 21:40
Autor Wiadomość
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ć?
C/C++
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 )
    {
        //inne bajery
    }
   
    // poruszaj kamera
   
    secCount +=( tim.getTime() /( double )( 1000000 ) );
    frameTime =( tim.getTime() /( double )( 1000 ) );
    if( frameTime < sixtyFPSFrameTime )
    {
        double timeWaste = sixtyFPSFrameTime - frameTime;
        //cout<<"timeWaste: "<<timeWaste<<endl;
        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
C/C++
#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 // V3DETIMER_HPP_INCLUDED
Timer.cpp
C/C++
#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();
        //cout<<"currentTime: "<<currentTime<<", startTime: "<<startTime<<", idleTime: "<<idleTime<<", stopTime"<<stopTime<<endl;
        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).
P-117880
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
C/C++
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.
P-117889
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:
C/C++
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();
        //cout<<"cos = "<<cos(-(calcRot.x) / 180 * XM_PI)*9<<"   /// sin = "<<sin(-(calcRot.z) / 180 * XM_PI)*9<<endl;
        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.
P-117891
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ą.
P-117892
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:
C/C++
namespace sf
{
    ////////////////////////////////////////////////////////////
    void sleep( Time duration )
    {
        if( duration >= Time::Zero )
             priv::sleepImpl( duration );
       
    }
   
} // namespace sf
A tutaj priv::sleepImpl:
C/C++
namespace sf
{
    namespace priv
    {
        ////////////////////////////////////////////////////////////
        void sleepImpl( Time time )
        {
            ::Sleep( time.asMilliseconds() );
        }
       
    } // namespace priv
   
} // namespace sf
P-117893
pekfos
» 2014-10-03 21:30:15
Nie wystarczy synchronizacja pionowa? Sleep() to bardzo słabe rozwiązanie.
P-117895
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%).
P-117899
« 1 »
  Strona 1 z 1