VSync per WinAPI ?

  • Moin,

    Im Verdacht habe ich das schon lange. Ob es wirklich zu 100% daran liegt kann ich leider nicht sagen.
    Deshalb gibts ein kleines Beispiel.

    Spoiler anzeigen
    [autoit]


    #include <GDIPlus.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Opt('GUIOnEventMode', 1)
    Opt('MustDeclareVars', 1)
    Opt('GUICloseOnESC', 0)

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $iFPS = 60
    Global Const $iW = 600, $iH = 480
    Global Const $sTitel = 'Test', $iSpeed = 5

    [/autoit] [autoit][/autoit] [autoit]

    Global $hGUI, $hIMG, $hDC, $hGFX, $hBUF, $hBRU

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    $hGUI = GUICreate($sTitel, $iW, $iH)
    $hIMG = _Image_Create($iW, $iH)
    $hBUF = DllStructGetData($hIMG, 1)
    $hDC = _WinAPI_GetDC($hGUI)
    $hGFX = _GDIPlus_GraphicsCreateFromHDC($hBUF)
    $hBRU = _GDIPlus_BrushCreateSolid(0xFFFFFFFF)

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState(@SW_SHOW, $hGUI)
    GUISetOnEvent(-3, '_Exit', $hGUI)
    GUIRegisterMsg(0xF, 'WM_PAINT')
    OnAutoItExitRegister('_Freigeben')

    [/autoit] [autoit][/autoit] [autoit]

    While FPS($iFPS)
    _GDIPlus_GraphicsClear($hGFX, 0xFF000000)
    _Rect()
    WM_PAINT()
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _Rect()
    Local Static $x = 0, $y = 100
    $x += $iSpeed * 60 / $iFPS
    If $x > $iW Then
    $x -= $iW + 64
    $y = Random(0, $iH - 64, 1)
    EndIf
    _GDIPlus_GraphicsFillRect($hGFX, $x, $y, 64, 64, $hBRU)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func FPS($W)
    Local Static $1 = TimerInit(), $2, $3
    Local $s = TimerDiff($1)
    $2 += (1000 / $W - $s)
    $3 = TimerInit()
    If $2 > 0 Then Sleep($2)
    $2 -= TimerDiff($3)
    $1 = TimerInit()
    Return True
    EndFunc ;==>_Sleep

    [/autoit] [autoit][/autoit] [autoit]

    Func WM_PAINT()
    Local Static $nFPS = 0, $iTimer = TimerInit()
    $nFPS += 1
    If TimerDiff($iTimer) > 1000 Then
    WinSetTitle($hGUI, '', $sTitel & ' FPS: ' & $nFPS)
    $iTimer = TimerInit()
    $nFPS = 0
    EndIf
    ;~ _WinAPI_RedrawWindow($hGUI)
    _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hBUF, 0, 0, 0xCC0020)

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    Exit
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Freigeben()
    _GDIPlus_BrushDispose($hBRU)
    _GDIPlus_GraphicsDispose($hGFX)
    _Image_Delete($hIMG)
    _GDIPlus_Shutdown()
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Image_Create($iW, $iH)
    Local $Ptr, $hDC, $hBmp, $tBMI, $aDIB, $vStruct
    $hDC = _WinAPI_CreateCompatibleDC(0)
    $tBMI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4)
    DllStructSetData($tBMI, "Width", $iW)
    DllStructSetData($tBMI, "Height", -$iH)
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", 32)
    $aDIB = DllCall('GDI32.DLL', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hBmp = $aDIB[0]
    $Ptr = $aDIB[4]
    _WinAPI_SelectObject($hDC, $hBmp)
    $vStruct = DllStructCreate('int[5]')
    DllStructSetData($vStruct, 1, $hDC, 1)
    DllStructSetData($vStruct, 1, $iW, 2)
    DllStructSetData($vStruct, 1, $iH, 3)
    DllStructSetData($vStruct, 1, $Ptr, 4)
    DllStructSetData($vStruct, 1, $hBmp, 5)
    Return $vStruct
    EndFunc ;==>_Image_Create

    [/autoit] [autoit][/autoit] [autoit]

    Func _Image_Delete(ByRef $vStruct)
    _WinAPI_DeleteObject(DllStructGetData($vStruct, 1, 5))
    _WinAPI_DeleteDC(DllStructGetData($vStruct, 1, 1))
    $vStruct = 0
    EndFunc ;==>_Image_Delete

    [/autoit]

    Zu sehen ist (bei mir jedenfalls) folgendes:
    Das Bild Ruckelt obwohl es mit 60 FPS läuft. (FPS einstellung auf euren Monitor anpassen in Zeile 8).
    Daraus schließe ich: Der Bildschirm überspringt öfters mal Einzelbilder. Es ist also nicht immer wenn das Skript Zeichnen will grade an der Zeit zu zeichnen.
    Stellt man die FPS auf exorbitante Werte (z.B. 2000 bei mir) läuft das Rechteck absolut flüssig. Das liegt daran, dass alle 60 Bilder in der Sekunde jeweils genau die Aktuelle Situation vorliegen haben.

    Nun möchte ich aber nicht 1940 FPS vergeigen (die wird mein Endprogramm eh nicht erreichen).
    Daher die Frage: Wie bekomme ich die ganze Sache Ruckelfrei (also mit dem Monitor synchronisiert).

    Mein Ansatz ist:
    Irgendwie muss ich jetzt eine Möglichkeit haben zu erfahren wann der Monitor fertig aktualisiert hat. (das müsste die Grafikkarte wissen)
    Nach der Aktualisierung wartet die Graka ja 17ms (bei 60 FPS) bis sie das nächste mal etwas an den Schirm schickt.
    In diesen 17ms (am besten unmittelbar) muss das neue Bild per BitBlt rübergeschaufelt werden. Dann müsste alles flüssig sein.

    Wenn jemand eine Idee hat möge er sich Melden.
    Ich bitte aber darum ein funktionierendes (oder nicht funktionierendes) Beispiel mitzubringen, sodass ich verstehe wie vorgegangen wurde.

  • Ich bin mir relativ sicher, dass sowohl GDI als auch GDIPlus das nicht unterstützen. Ich habe auch in anderen Programmiersprachen noch keine Möglichkeit gefunden sie dazu zu bringen. Ob das also direkt per WinAPI geht ist fraglich, ich glaube es nicht.
    Die neueren Grafikbibliotheken - DirectX (z.B. DirectDraw) etc. - sollten das von Haus aus unterstützen, falls du das als Alternative in Betracht ziehst. ;) Eventuell kann man auch beide Grafiklösungen kombinieren, aber je nach Aufwand lohnt sich das vielleicht nicht.
    Ansonsten müsste man irgendwie eine andere, externe Möglichkeit finden den VBI des Monitors mitzukriegen. Normalerweise macht man das ja über die Grafikkarte und deren Treiber wenn mich nicht alles täuscht, aber ob man da mit AutoIt rankommt kann ich nicht sagen. Vor allem weiß ich nicht wie sich da die einzelnen Grafikkarten unterscheiden...

    Naja, vielleicht kommt jetzt noch einer unserer genialen Köpfe vorbei (Andy, UEZ, eukalyptus etc. :D) und präsentiert dir hier die Lösung auf dem Silberteller. Hoffen kann man ja ;).

    Zitat von IPU

    Das Problem was hier auftritt lässt sich vermutlich aber mit dem klassischen Backbuffer beheben (Beispiele wie sowas aussieht in AutoIT findet man z.B. hier) - ich hätts dir zwar auch auf die Schnelle in dein Script bauen können, aber dazu hätte ich das Script in meinem müden Kopf kapieren müssen. Hoffe, dass dir das trotz allem hilft. ;)

    Würde mich interessieren wie du das einbauen willst, wenn es bereits im Script vorhanden ist.

  • Im Fenstermodus ist das schlicht unmöglich.
    Ab Windows7 mit Aero oder Windows 8 sollte eigentlich das Betriebssystem auf den Vsync warten,
    aber das funktioniert nicht wirklich.
    Mit DirectX, vor allem im Vollbildmodus muss es klappen.
    ...animierte Grafik mit DirectX in AutoIt ? Au Backe! ;(

    Wer andern eine Bratwurst brät
    der hat ein Bratwurstbratgerät.

  • Im Fenstermodus ist das schlicht unmöglich.

    Edit: Achso grade das Zitat vergessen^^
    Ich will nicht den ganzen Schirm anpassen, sondern nur eine Möglichkeit im Skript herauszufinden wann der Bildschirm aktualisiert wurde. Dann kann man mit einem unmittelbaren BitBlt eventuell immer den richtigen Zeitpunkt erwischen.
    Ich benutze zurzeit Win8. Auf anderen Systemen habe ich es jetzt nicht getestet. Das Resultat müsste abwärts aber gleich sein.

    Hab das Beispiel mal von GDI auf GDI+ angepasst. (Anderer Backbuffer -> DrawImage statt BitBlt)

    Spoiler anzeigen
    [autoit]

    #include <GDIPlus.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Opt('GUIOnEventMode', 1)
    Opt('MustDeclareVars', 1)
    Opt('GUICloseOnESC', 0)

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $iFPS = 60
    Global Const $iW = 600, $iH = 480
    Global Const $sTitel = 'Test', $iSpeed = 5

    [/autoit] [autoit][/autoit] [autoit]

    Global $hGUI, $hIMG, $hDC, $hGFX, $hBUF, $hBRU, $hGFX_GUI, $hBMP

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    $hGUI = GUICreate($sTitel, $iW, $iH)
    $hIMG = _Image_Create($iW, $iH) ; Hier gammelt ein Backbuffer
    $hBUF = DllStructGetData($hIMG, 1)
    $hDC = _WinAPI_GetDC($hGUI)
    $hGFX_GUI = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBMP = _GDIPlus_BitmapCreateFromGraphics($iW, $iH, $hGFX_GUI)
    $hGFX = _GDIPlus_ImageGetGraphicsContext($hBmp)
    $hBRU = _GDIPlus_BrushCreateSolid(0xFFFFFFFF)

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState(@SW_SHOW, $hGUI)
    GUISetOnEvent(-3, '_Exit', $hGUI)
    GUIRegisterMsg(0xF, 'WM_PAINT')
    OnAutoItExitRegister('_Freigeben')

    [/autoit] [autoit][/autoit] [autoit]

    While FPS($iFPS)
    _GDIPlus_GraphicsClear($hGFX, 0xFF000000)
    _Rect()
    WM_PAINT()
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _Rect()
    Local Static $x = 0, $y = 100
    $x += $iSpeed * 60 / $iFPS
    If $x > $iW Then
    $x -= $iW + 64
    $y = Random(0, $iH - 64, 1)
    EndIf
    _GDIPlus_GraphicsFillRect($hGFX, $x, $y, 64, 64, $hBRU)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func WM_PAINT()
    Local Static $nFPS = 0, $iTimer = TimerInit()
    $nFPS += 1
    If TimerDiff($iTimer) > 1000 Then
    WinSetTitle($hGUI, '', $sTitel & ' FPS: ' & $nFPS)
    $iTimer = TimerInit()
    $nFPS = 0
    EndIf
    ;~ _WinAPI_RedrawWindow($hGUI)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_GraphicsDrawImage($hGFX_GUI, $hBMP, 0, 0)
    ;~ _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hBUF, 0, 0, 0xCC0020)

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func FPS($W)
    Local Static $1 = TimerInit(), $2, $3
    Local $s = TimerDiff($1)
    $2 += (1000 / $W - $s)
    $3 = TimerInit()
    If $2 > 0 Then Sleep($2)
    $2 -= TimerDiff($3)
    $1 = TimerInit()
    Return True
    EndFunc ;==>_Sleep

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    Exit
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Freigeben()
    _GDIPlus_BrushDispose($hBRU)
    _GDIPlus_GraphicsDispose($hGFX)
    _GDIPlus_GraphicsDispose($hGFX_GUI)
    _GDIPlus_BitmapDispose($hBMP)
    _Image_Delete($hIMG)
    _GDIPlus_Shutdown()
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Image_Create($iW, $iH)
    Local $Ptr, $hDC, $hBmp, $tBMI, $aDIB, $vStruct
    $hDC = _WinAPI_CreateCompatibleDC(0)
    $tBMI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4)
    DllStructSetData($tBMI, "Width", $iW)
    DllStructSetData($tBMI, "Height", -$iH)
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", 32)
    $aDIB = DllCall('GDI32.DLL', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hBmp = $aDIB[0]
    $Ptr = $aDIB[4]
    _WinAPI_SelectObject($hDC, $hBmp)
    $vStruct = DllStructCreate('int[5]')
    DllStructSetData($vStruct, 1, $hDC, 1)
    DllStructSetData($vStruct, 1, $iW, 2)
    DllStructSetData($vStruct, 1, $iH, 3)
    DllStructSetData($vStruct, 1, $Ptr, 4)
    DllStructSetData($vStruct, 1, $hBmp, 5)
    Return $vStruct
    EndFunc ;==>_Image_Create

    [/autoit] [autoit][/autoit] [autoit]

    Func _Image_Delete(ByRef $vStruct)
    _WinAPI_DeleteObject(DllStructGetData($vStruct, 1, 5))
    _WinAPI_DeleteDC(DllStructGetData($vStruct, 1, 1))
    $vStruct = 0
    EndFunc ;==>_Image_Delete

    [/autoit]

    Resultat (bei mir):
    Es ruckelt ein bisschen weniger.
    GDI+ ist ebenfalls nicht synchron. Das Rechteck wird "zerrissen". Das Zeichnen dauert also so lange, dass der Schirm wärend dem Zeichenvorgang aktualisiert wird. Dadurch ist das Rechteck manchmal zur Hälfte einen Frame weiter, also kaputt.

  • Ich gebe zu, ich habe mich geirrt. Es geht doch im Fenstermodus.
    Hier ist ein Artikel zum Thema mit Beispiel in C++ : http://www.codeproject.com/Articles/4436/…rawing-with-GDI
    Ich habs ausprobiert, sieht sehr gut aus. (Klick im Menü auf "On Screen Display"!)
    DirectX wird benutzt, um den vSync zu finden, dann ein präziser Timer und schliesslich GDI zum "Blitten".
    Sehr umständlich, aber finde mal eine bessere Methode...

    Wer andern eine Bratwurst brät
    der hat ein Bratwurstbratgerät.

    Einmal editiert, zuletzt von ohforf (9. Januar 2013 um 16:57)

  • Das sieht nach dem Aus was ich meinte.
    Ich habe aber leider keinen Plan wie ich DirectX in AutoIt nutzen kann.

    Wenn jemand weiß wie es geht bitte ich darum ein AutoIt Beispiel zu erstellen.
    Daraus kann ich besser die Funktionsweise erlernen als aus Text.

    Edit:
    Ich hab ne Idee (die ist aber total bekloppt^^)
    Wenn der BitBlt erfolgreich am richtigen Zeitpunkt geschieht müsste die Dauer des Funktionsaufrufs variieren. (Sie müsste geringer sein als wenn ich zum falschen Zeitpunkt blitte, den zum richtigen Zeitpunkt funkt kein ander Prozess dazwischen und liest die Bitmapdaten in die ich grade schreiben will.
    Mal schauen ob das klappt. Wäre gegen jede Regel, aber villeicht funktionierts^^

  • Hi,
    idR. kannst du das bei den Treibereinstellungen der Grafikkarte einstellen.
    Vertikale Synchronisierung oder VSYNC....mit den Einstellungen dort mal bissl rumspielen.
    Auch ist das Triple- dem Doublebuffering vorzuziehen!

    Wenn die VSYNC eingeschaltet ist, stellt die Grafikkarte nur Bilder synchron zur Bildwiederholfrequenz des Monitors ein (TFT 60Hz)
    Das führt dann in ungünstigen Fällen dazu, dass es bei den fixen 60Hz Bildwiederholfrequenz zu "Sprüngen" in der Bildrate (FPS) kommt, wenn die FPS in einem Bereich liegen, der ein Vielfaches bzw ein ganzzahliger Teiler der 60Hz ist.
    Denn die Grafikkarte synchronisiert dann die FPS mit der (Monitor-)Bildwiederholfrequenz. Das geht natürlich nur glatt auf, wenn die 60Hz ein Vielfaches der Bildrate ist.
    Bei 62FPS werden 60Hz dargestellt, bei 58fps nur noch 30fps dargestellt, also nur ganzzzahlige Teiler von 60.
    Wenn deine Graka also in der einen Sekunde 62 Bilder rendert, und in der anderen nur 58, dann kommt es zu Sprüngen in den dargestellten Frames, nämlich einmal 60 und das andere Mal 30. Und diesen "Unterschied" bzw "Verzögerung" zwischen 2 aufeinanderfolgenden Bildern (ca 33ms) sieht man dann als Ruckler.

    Als Abhilfe könnte man das VSYNC doch einfach ausschalten, das führt aber dann bei einer SEHR hohen Bildrate zum sog. "Tearing". Will heissen, die Grafikkarte ist so schnell, dass sie schon eine neues Bild liefert, obwohl der Monitor das "alte" noch nicht vollständig ausgegeben hat. Bei schnellen horizontalen Kameraschwenks merkt man das besonders deutlich an zerhackten bzw. zerissenen Bildern.

    Daher muss ich immer schmunzeln, wenn ich lese/höre (Gamerforen sind voll von diesen Sprüchen) dass div. Leute bei Ballerspielen den Unterschied zw. 70 und 120FPS "sehen". Coole Sache, denn der Monitor stellt ja nur maximal 60 Bilder pro Sekunde dar, völlig egal, ob die Graka 12345tausend FPS liefert^^
    Bei niedrigen FPS macht hingegen das "Tuning" schon viel aus, denn es ist ein Unterschied, ob der Monitor bei 19FPS nur 15FPS (60/4)darstellt(s.o.) oder bei 21 FPS eben dann 20FPS(60/3) darstellt.
    Bei aktivem VSYNC und 29FPS hat man gelitten, denn der Monitor stellt nur 60/3=20 FPS dar, mal eben 30% der Leistung der Graka in den Wind geblasen^^. Die Auflösung bissl reduzieren und das AA runterschrauben, und schwupps, "sieht" man plötzlich 30FPS.....

  • Hmm... Hab jetzt mal was wirklich primitives getestet und siehe da: Ohne Offset läufts auch (komischerweise)
    Es wird jetzt per Timer alle x ms die Funktion ausgeführt. Nachteil ist die Hohe Schleifenfrequenz. Das kann man aber mit einem kleinen Trick umgehen.
    Offseteinstellung über die Pfeiltasten. Scheint aber ohne wirkung zu sein, was mich überrascht...

    Spoiler anzeigen
    [autoit]

    #include <GDIPlus.au3>
    #include <Misc.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Opt('GUIOnEventMode', 1)
    Opt('MustDeclareVars', 1)
    Opt('GUICloseOnESC', 0)

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $iFPS = 60
    Global Const $iW = 600, $iH = 480
    Global Const $sTitel = 'Test', $iSpeed = 5

    [/autoit] [autoit][/autoit] [autoit]

    Global $hGUI, $hIMG, $hDC, $hGFX, $hBUF, $hBRU

    [/autoit] [autoit][/autoit] [autoit]

    Global $vSyncTimer = TimerInit(), $vSyncOffset = 0, $vSyncTemp = 0, $vSyncDiff = 1000/$iFPS

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    $hGUI = GUICreate($sTitel, $iW, $iH)
    $hIMG = _Image_Create($iW, $iH)
    $hBUF = DllStructGetData($hIMG, 1)
    $hDC = _WinAPI_GetDC($hGUI)
    $hGFX = _GDIPlus_GraphicsCreateFromHDC($hBUF)
    $hBRU = _GDIPlus_BrushCreateSolid(0xFFFFFFFF)

    [/autoit] [autoit][/autoit] [autoit]

    GUISetState(@SW_SHOW, $hGUI)
    GUISetOnEvent(-3, '_Exit', $hGUI)
    GUIRegisterMsg(0xF, 'WM_PAINT')
    OnAutoItExitRegister('_Freigeben')

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    If TimerDiff($vSyncTimer) > $vSyncTemp + $vSyncOffset Then
    $vSyncTemp += $vSyncDiff
    _GDIPlus_GraphicsClear($hGFX, 0xFF000000)
    _Rect()
    WM_PAINT()
    ToolTip($vSyncOffset)
    If _IsPressed('26') Then $vSyncOffset += 0.1
    If _IsPressed('28') Then $vSyncOffset -= 0.1
    If $vSyncOffset > $vSyncDiff Then $vSyncOffset -= $vSyncDiff
    If $vSyncOffset < 0 Then $vSyncOffset += $vSyncDiff
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _Rect()
    Local Static $x = 0, $y = 100
    $x += $iSpeed * 60 / $iFPS
    If $x > $iW Then
    $x -= $iW + 64
    $y = Random(0, $iH - 64, 1)
    EndIf
    _GDIPlus_GraphicsFillRect($hGFX, $x, $y, 64, 64, $hBRU)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func FPS($W)
    Local Static $1 = TimerInit(), $2, $3
    Local $s = TimerDiff($1)
    $2 += (1000 / $W - $s)
    $3 = TimerInit()
    If $2 > 0 Then Sleep($2)
    $2 -= TimerDiff($3)
    $1 = TimerInit()
    Return True
    EndFunc ;==>_Sleep

    [/autoit] [autoit][/autoit] [autoit]

    Func WM_PAINT()
    Local Static $nFPS = 0, $iTimer = TimerInit()
    $nFPS += 1
    If TimerDiff($iTimer) > 1000 Then
    WinSetTitle($hGUI, '', $sTitel & ' FPS: ' & $nFPS)
    $iTimer = TimerInit()
    $nFPS = 0
    EndIf
    ;~ _WinAPI_RedrawWindow($hGUI)
    _WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hBUF, 0, 0, 0xCC0020)

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    Exit
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Freigeben()
    _GDIPlus_BrushDispose($hBRU)
    _GDIPlus_GraphicsDispose($hGFX)
    _Image_Delete($hIMG)
    _GDIPlus_Shutdown()
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Image_Create($iW, $iH)
    Local $Ptr, $hDC, $hBmp, $tBMI, $aDIB, $vStruct
    $hDC = _WinAPI_CreateCompatibleDC(0)
    $tBMI = DllStructCreate($tagBITMAPINFO)
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4)
    DllStructSetData($tBMI, "Width", $iW)
    DllStructSetData($tBMI, "Height", -$iH)
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", 32)
    $aDIB = DllCall('GDI32.DLL', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hBmp = $aDIB[0]
    $Ptr = $aDIB[4]
    _WinAPI_SelectObject($hDC, $hBmp)
    $vStruct = DllStructCreate('int[5]')
    DllStructSetData($vStruct, 1, $hDC, 1)
    DllStructSetData($vStruct, 1, $iW, 2)
    DllStructSetData($vStruct, 1, $iH, 3)
    DllStructSetData($vStruct, 1, $Ptr, 4)
    DllStructSetData($vStruct, 1, $hBmp, 5)
    Return $vStruct
    EndFunc ;==>_Image_Create

    [/autoit] [autoit][/autoit] [autoit]

    Func _Image_Delete(ByRef $vStruct)
    _WinAPI_DeleteObject(DllStructGetData($vStruct, 1, 5))
    _WinAPI_DeleteDC(DllStructGetData($vStruct, 1, 1))
    $vStruct = 0
    EndFunc ;==>_Image_Delete

    [/autoit]


    Edit: Alle 1-2 Sekunden Ruckeln aber dennoch 1-2 Frames.
    Wie komme ich an die exakte Frequenz des Bildschirms ? 60 scheint es nicht zu sein...

  • Wow, Andy kennt sich echt verdammt gut aus :)
    Aber theoretisch kann man seinen Monitor doch auch auf 75Hz stellen, oder? Dann ist das doch wieder ganz anders... Macht das Sinn, seinen Monitor auf 75 Hz zu stellen?

    Da es hier doch einige falsch machen:

    Zitat von einem User dieses Forums

    Die Standard-Standart eines Flamingos ist einbeinig. ;)

  • Hi Mars(i)

    Ich kann dein Ergebnis (die paar Frameruckler ehrlich gesagt nicht nachvollziehen)
    Ich hab das kleine Ding mal zum Testen 2 Minuten laufen lassen, Bei mir kommt es zu absolut keinen Rucklern.

    Im Tooltip hab Ich auch nur eine simple 0 stehen.

    Edit: Ah jetzt weiß Ich wofür der Tooltip da ist.
    Hab mal grob jeden Wert durchgegangen mit den Pfeiltasten. Aber immer das selbe Ergebnis wie oben

    lg,

  • Hi,
    in XP kommt man über Eigenschaften Anzeige, Einstellungen, Erweitert, Reiter Monitor zur Bildschirmaktualisierungsrate.

    Zitat

    Aber theoretisch kann man seinen Monitor doch auch auf 75Hz stellen, oder? Dann ist das doch wieder ganz anders... Macht das Sinn, seinen Monitor auf 75 Hz zu stellen?


    Bei einem digital angesteuerten Flachbildschirm, macht das imho keinen Sinn. Die Bildqualität/Flimmern ist bei allen Frequenzen identisch (wieso sonst sollte man ein Display digital ansteuern^^ ) allerdings steigt bei zunehmender Monitorfrequenz natürlich auch die Transferlast auf den Speicher der Grafikkarte.
    Kurzes Beispiel:
    Monitor Auflösung 1920x1080, 32BitPerPixel(=4BytepP) und 60 Hz => 1920*1080*4 Byte * 60 1/s = 498 MByte/s
    Monitor Auflösung 1920x1080, 32BitPerPixel(=4BytepP) und 85 Hz => 1920*1080*4 Byte * 85 1/s = 705 MByte/s

    Röhrenmonitore sollte man immer mit der vom Monitor und Grafikkarte höchsten verfügbaren Frequenz ansteuern, um Flimmern zu minimieren.

    Bei analog angesteuerten digitalen Monitoren sollte man auch die niedrigste Monitorfrequenz einstellen, das kann die Bilddarstellung teilweise deutlich verbessern, da die "analogen" Störungen durch Kabel, Steckverbinder usw. die verfügbare Bandbreite für das Signal einschränken können. Weniger Bildwiederholfrequenz => weniger benötigte Bandbreite => besseres Signal => besseres Bild 8)