FloatingPoint-Zahlen für SLI-Harmonizer C++ 

Status
Für weitere Antworten geschlossen.

didic

Registered +
Registriert
Aug. 2007
Beiträge
158
Hallo @ all

Ich kann leider fast nur Java programmieren, deshalb habe ich folgendes Problem:
Beim SLI-Harmonizer, der die berechneten Bilder pro Sekunde der Grafikkarten in einem System beschränken soll, besteht das Problem, dass die Zahlen für die Intervalle (in ms, "1000/xx") immer ganzzahlig betrachet werden (in Java wärs zB. "double").

Dies führt dann in der Ausführung zu Ungenauigkeiten, zB. 50 statt 48 frames/s, was an sich nicht sonderlich schlimm ist, allerdings wenn man z.B. eine Framerate wählen will, die mit der Frequenz des Monitors Hand in Hand geht, führt dies zu Problemen.

Deshalb möchte ich die Intervall-Timings als FloatingPoint-Zahlen definieren und verwenden.
Es ist wohl nicht sehr kompliziert, doch ich kann es einfach nicht...:löl:
Ausserdem stellt sich die Frage, ob dies (spürbar) mehr Leistung vom System abverlangt.:confused:

Der Code:
Code:
[COLOR='darkgreen']// timer.cpp : Defines the entry point for the DLL application.
//[/COLOR]

#include "stdafx.h"
#include "timer.h"


#ifdef _MANAGED
#pragma managed(push, off)
#endif

[COLOR='darkgreen']// simple timer class[/COLOR]
#pragma pack(push, 8)

class SimpleTimer{
private:
__int64 m_frequency;

__int64 m_baseTime;

__int64 t;

__int64 lastTime;

__int64 thisTime;

__int64 newTime;
public:

__int64 elapsed()
{
newTime=0;
QueryPerformanceCounter(reinterpret_cast(&newTime));
t = (newTime - m_baseTime)/m_frequency;
m_baseTime=newTime;
return t;
}


SimpleTimer()
{
init();
}

~SimpleTimer()
{
}

void init()
{
m_frequency=m_baseTime=thisTime=lastTime=0;
QueryPerformanceFrequency(reinterpret_cast(&m_frequency));
QueryPerformanceCounter(reinterpret_cast(&m_baseTime));
m_frequency/=1000;
}

};
#pragma pack(pop)

SimpleTimer *myTimer=NULL;



BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
if(!myTimer)
myTimer=new SimpleTimer();
break;

case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;

case DLL_PROCESS_DETACH:
if(myTimer)
delete myTimer;
myTimer=NULL;
break;
}
return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif

const int framesToConsider=2;

extern "C"{

__declspec(dllexport) void waitFunction()
{
if(!myTimer)
return;
[COLOR='DarkGreen']/*

* Monitoring der letzten 2/3/4 frames (SLI/T-SLI/Q-SLI)
* Bestimmung der durchschnittlichen frametime
* Verzögerung der Ausgabe in Abhängigkeit vom Durchschnitt für die nächsten 2/3/4 frames

*/[/COLOR]

static int callCounter=0;
static long timeToWait=0;
static long lastFramesTime[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static long lastFramesTotalTime=0;
static char tmp[1024];

lastFramesTime[callCounter]=myTimer->elapsed();

[COLOR='darkgreen']//sprintf(tmp, "\ntotal %d frame(%d) time %d", (1000/30), callCounter, lastFramesTime[callCounter]);
//OutputDebugStringA(tmp);

// limit to 30 fps[/COLOR]

if(lastFramesTime[callCounter]30[/COLOR]))
{
timeToWait=([COLOR='red']1000/30[/COLOR])-lastFramesTime[callCounter];
Sleep(timeToWait);
myTimer->elapsed(); // reset timer, otherwise the next frame will be too long
}
}

}

Vielen Dank schonmal an alle für die Hilfe!

mfg didic
 
Deshalb möchte ich die Intervall-Timings als FloatingPoint-Zahlen definieren und verwenden.
Na dann mach es doch. :/

Was ist jetzt die Frage, wie man Fliesskommazahlen in C++ darstellt? o0
Genauso wie in Java:

Code:
float a = 24.0f;
double b = 24.0;
 
Hmm, danke erstmal für die Antwort.

Nun sind die Zahlen hier ja direkt in den "Ablauf" geschrieben (nicht als Variable), kann ich es dann einfach so casten wie in Java?
Code:
((float)1000/30)

mfg


EDIT:

Folgendes hat nichts gebracht, immer noch 50 fps anstatt 48:
Code:
[B]...[/B]

static int callCounter=0;
static [COLOR='Blue']float [/COLOR]timeToWait=0;
static [COLOR='blue']float [/COLOR]lastFramesTime[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static [COLOR='blue']float [/COLOR]lastFramesTotalTime=0;
static char tmp[1024];

lastFramesTime[callCounter]=myTimer->elapsed();

[COLOR='DarkGreen'] //sprintf(tmp, "\ntotal %d frame(%d) time %d", (1000/30), callCounter, lastFramesTime[callCounter]);
//OutputDebugStringA(tmp);

// limit to 30 fps[/COLOR]
if(lastFramesTime[callCounter]48))
{
timeToWait=(1000/48)-lastFramesTime[callCounter];
[COLOR='Purple'] Sleep(timeToWait);[/COLOR]
myTimer->elapsed(); // reset timer, otherwise the next frame will be too long
}

[B]...[/B]

Das Blaue sind die geänderten Werte, das Violette ist die Zeile, wo ich den Fehler vermute: Funktioniert die Sleep-Methode nur mit ganzen Zahlen (ms)? Gibt es eine Alternative, die genauer arbeitet?

mfg
 
Zuletzt bearbeitet von einem Moderator:
Also in der Hilfe vom VS steht zur Sleep Funktion
das der Wert für "timeToWait" ein DWORD ist und das ganze in ms.
Sonst hilft da nur der Debugger...

Grüsse
biernase
 
Achso, jetzt versteh ich dein Problem.
Ja also sleep funktioniert nur mit Ganzzahlen.

Was du also wohl nur machen kannst, ist die ganze Zeit mit floats zu rechnen und beim sleep() Aufruf in int zu casten.

Hmm, danke erstmal für die Antwort.

Nun sind die Zahlen hier ja direkt in den "Ablauf" geschrieben (nicht als Variable), kann ich es dann einfach so casten wie in Java?
Code:
((float)1000/30)
Ja, du kannst es so casten wie in Java, aber selbst in Java macht man es nicht so. ;)
Es wird wahrscheinlich folgendes passieren:
Er rechnet 1000/30 = 33, dann castet er zu float = 33.0f.
Schreib lieber einfach 1000.0f/30.0f, dann ist das Ergebnis auf jeden Fall float.

Code:
static int callCounter=0;
static float timeToWait=0.0f;
static float lastFramesTime[16]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f};
static float lastFramesTotalTime=0.0f;
static char tmp[1024];

lastFramesTime[callCounter]=myTimer->elapsed();

//sprintf(tmp, "\ntotal %d frame(%d) time %d", (1000/30), callCounter, lastFramesTime[callCounter]);
//OutputDebugStringA(tmp);

// limit to 30 fps
if(lastFramesTime[callCounter]48.0f[/COLOR]))
{
timeToWait=([COLOR='Red']1000.0f/48.0f[/COLOR])-lastFramesTime[callCounter];
Sleep((int)timeToWait);
myTimer->elapsed(); // reset timer, otherwise the next frame will be too long
}


Edit:
Achso, und noch eine Moeglichkeit ist halt, dass du einfach die Zahlen selbst veraenderst.
Z.B. wenn du alles mit Ganzzahlen laesst, dann muesstest du mit 1000/46 und 1000/47 48fps haben.
Aber da oben hast du ja 1000/30 und jetzt ist es 1000/48.
Und beide Male hattest du 50fps?
Denn dann siehts so aus, als ob der Code keinen Einfluss auf die fps hat.^^
 
Zuletzt bearbeitet von einem Moderator:
Du willst mit float rechnen, also musst du auch float werte benutzen...

schreibst du sowas:
PHP:
float variable = 1000/48;
wirst du als ergebnis 20.0000 rausbekommen

Der Kompiler behandelt die werte 1000 und 48 als integer werte, da du diese auch so definiert hast. Um sie als float zu benutzen musst du den suffix .0f anhängen. Also:
PHP:
float variable = 1000.0f/48.0f;
Das Ergebnis sollte dann 20.83333 sein

*edit*
mist zu langsam ;)
 
Zuletzt bearbeitet von einem Moderator:
Ok, danke für die Antworten.

Das oben war nur Standart für 30 fps :D.

Das Ganze funktioniert schon, doch nun ist es ja folgendes Problem:

1000/48 = 20.83333333333333...
Wenn ich das nun in der Sleep-Funktion caste, wird das Frame auf 20 ms gekürzt, folglich passen dann 50 Frames in eine Sekunde.

Ein würg-around wäre ja, eine Fallunterscheidung einzuführen, im Sinne von zuerst 5 Mal 21 ms und einmal 20 ms, wieder 5x 21 ms usw...
Doch ich fände dies etwas zu Kompliziert und ausserdem etwas unsauber.

Gibt es denn keine bessere Lösung?

mfg
 
Zuletzt bearbeitet von einem Moderator:
Status
Für weitere Antworten geschlossen.
Zurück
Oben Unten