FloatingPoint-Zahlen für SLI-Harmonizer

  • C++

  • didic
  • 975 Aufrufe 8 Antworten

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • FloatingPoint-Zahlen für SLI-Harmonizer

    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:

    C-Quellcode

    1. [COLOR='darkgreen']// timer.cpp : Defines the entry point for the DLL application.
    2. //[/COLOR]
    3. #include "stdafx.h"
    4. #include "timer.h"
    5. #ifdef _MANAGED
    6. #pragma managed(push, off)
    7. #endif
    8. [COLOR='darkgreen']// simple timer class[/COLOR]
    9. #pragma pack(push, 8)
    10. class SimpleTimer{
    11. private:
    12. __int64 m_frequency;
    13. __int64 m_baseTime;
    14. __int64 t;
    15. __int64 lastTime;
    16. __int64 thisTime;
    17. __int64 newTime;
    18. public:
    19. __int64 elapsed()
    20. {
    21. newTime=0;
    22. QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&newTime));
    23. t = (newTime - m_baseTime)/m_frequency;
    24. m_baseTime=newTime;
    25. return t;
    26. }
    27. SimpleTimer()
    28. {
    29. init();
    30. }
    31. ~SimpleTimer()
    32. {
    33. }
    34. void init()
    35. {
    36. m_frequency=m_baseTime=thisTime=lastTime=0;
    37. QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(&m_frequency));
    38. QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&m_baseTime));
    39. m_frequency/=1000;
    40. }
    41. };
    42. #pragma pack(pop)
    43. SimpleTimer *myTimer=NULL;
    44. BOOL APIENTRY DllMain( HMODULE hModule,
    45. DWORD ul_reason_for_call,
    46. LPVOID lpReserved
    47. )
    48. {
    49. switch (ul_reason_for_call)
    50. {
    51. case DLL_PROCESS_ATTACH:
    52. if(!myTimer)
    53. myTimer=new SimpleTimer();
    54. break;
    55. case DLL_THREAD_ATTACH:
    56. break;
    57. case DLL_THREAD_DETACH:
    58. break;
    59. case DLL_PROCESS_DETACH:
    60. if(myTimer)
    61. delete myTimer;
    62. myTimer=NULL;
    63. break;
    64. }
    65. return TRUE;
    66. }
    67. #ifdef _MANAGED
    68. #pragma managed(pop)
    69. #endif
    70. const int framesToConsider=2;
    71. extern "C"{
    72. __declspec(dllexport) void waitFunction()
    73. {
    74. if(!myTimer)
    75. return;
    76. [COLOR='DarkGreen']/*
    77. * Monitoring der letzten 2/3/4 frames (SLI/T-SLI/Q-SLI)
    78. * Bestimmung der durchschnittlichen frametime
    79. * Verzögerung der Ausgabe in Abhängigkeit vom Durchschnitt für die nächsten 2/3/4 frames
    80. */[/COLOR]
    81. static int callCounter=0;
    82. static long timeToWait=0;
    83. static long lastFramesTime[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    84. static long lastFramesTotalTime=0;
    85. static char tmp[1024];
    86. lastFramesTime[callCounter]=myTimer->elapsed();
    87. [COLOR='darkgreen']//sprintf(tmp, "\ntotal %d frame(%d) time %d", (1000/30), callCounter, lastFramesTime[callCounter]);
    88. //OutputDebugStringA(tmp);
    89. // limit to 30 fps[/COLOR]
    90. if(lastFramesTime[callCounter]<([COLOR='Red']1000/30[/COLOR]))
    91. {
    92. timeToWait=([COLOR='red']1000/30[/COLOR])-lastFramesTime[callCounter];
    93. Sleep(timeToWait);
    94. myTimer->elapsed(); // reset timer, otherwise the next frame will be too long
    95. }
    96. }
    97. }
    Alles anzeigen


    Vielen Dank schonmal an alle für die Hilfe!

    mfg didic
    iouRzer9"iuz74g8974t89?oz&4it0zh9(/H3gf7 ...
  • 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?

    Quellcode

    1. ((float)1000/30)


    mfg


    EDIT:

    Folgendes hat nichts gebracht, immer noch 50 fps anstatt 48:

    Quellcode

    1. [B]...[/B]
    2. static int callCounter=0;
    3. static [COLOR='Blue']float [/COLOR]timeToWait=0;
    4. static [COLOR='blue']float [/COLOR]lastFramesTime[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    5. static [COLOR='blue']float [/COLOR]lastFramesTotalTime=0;
    6. static char tmp[1024];
    7. lastFramesTime[callCounter]=myTimer->elapsed();
    8. [COLOR='DarkGreen'] //sprintf(tmp, "\ntotal %d frame(%d) time %d", (1000/30), callCounter, lastFramesTime[callCounter]);
    9. //OutputDebugStringA(tmp);
    10. // limit to 30 fps[/COLOR]
    11. if(lastFramesTime[callCounter]<(1000/48))
    12. {
    13. timeToWait=(1000/48)-lastFramesTime[callCounter];
    14. [COLOR='Purple'] Sleep(timeToWait);[/COLOR]
    15. myTimer->elapsed(); // reset timer, otherwise the next frame will be too long
    16. }
    17. [B]...[/B]
    Alles anzeigen


    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
    iouRzer9"iuz74g8974t89?oz&4it0zh9(/H3gf7 ...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von didic ()

  • 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.

    didic schrieb:

    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?

    Quellcode

    1. ((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.

    Quellcode

    1. static int callCounter=0;
    2. static float timeToWait=0.0f;
    3. 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};
    4. static float lastFramesTotalTime=0.0f;
    5. static char tmp[1024];
    6. lastFramesTime[callCounter]=myTimer->elapsed();
    7. //sprintf(tmp, "\ntotal %d frame(%d) time %d", (1000/30), callCounter, lastFramesTime[callCounter]);
    8. //OutputDebugStringA(tmp);
    9. // limit to 30 fps
    10. if(lastFramesTime[callCounter]<([COLOR='Red']1000.0f/48.0f[/COLOR]))
    11. {
    12. timeToWait=([COLOR='Red']1000.0f/48.0f[/COLOR])-lastFramesTime[callCounter];
    13. Sleep((int)timeToWait);
    14. myTimer->elapsed(); // reset timer, otherwise the next frame will be too long
    15. }
    Alles anzeigen



    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.^^
    Wo ist der Discord Server

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von Skyte ()

  • Du willst mit float rechnen, also musst du auch float werte benutzen...

    schreibst du sowas:

    PHP-Quellcode

    1. 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-Quellcode

    1. float variable = 1000.0f/48.0f;

    Das Ergebnis sollte dann 20.83333 sein

    *edit*
    mist zu langsam ;)
    [SIZE="1"]i'm a signature virus. copy me into your signature to help me spread. - smart questions[/SIZE]

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Zerd ()

  • 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
    iouRzer9"iuz74g8974t89?oz&4it0zh9(/H3gf7 ...
  • didic schrieb:

    Gibt es denn keine bessere Lösung?

    Wie ich schon sagte:

    Skyte schrieb:

    Z.B. wenn du alles mit Ganzzahlen laesst, dann muesstest du mit 1000/46 und 1000/47 48fps haben.

    Aber sind halt nicht genau 48fps, sondern 47,6.


    Ansonsten kommste um ein If nicht rum:

    Quellcode

    1. int a;
    2. int i = 0;

    Quellcode

    1. if (i=++i%6) a = 21;
    2. else a = 20;
    3. sleep(a);
    Wo ist der Discord Server

    Dieser Beitrag wurde bereits 11 mal editiert, zuletzt von Skyte ()