Schlechte GDI+ Performance auf WinXP

  • Hi,

    wenn ich das GDI+ Programm auf meiner Kiste mit nVidia 8800GT laufen lasse, dann ist die Performance so schlecht, dass man die Pixel einzeln zählen kann.

    Kann jemand das auch bestätigen?

    Meine Kiste:
    WinXP Pro SP3
    Intel Core Duo @ 2.5 GHz
    nVidia 8800GT (neueste Treiber! War auch genauso mit Älteren)

    Mit einigen anderen GDI+ Codes, wie z.B. AUTOITEROIDS, und auf meinen 2 Notebooks gibt es keine Probleme!

    Hier der Code:

    Spoiler anzeigen

    #AutoIt3Wrapper_Run_Obfuscator=y
    #Obfuscator_Parameters=/so
    #AutoIt3Wrapper_Res_SaveSource=n
    #AutoIt3Wrapper_UseUpx=n
    #AutoIt3Wrapper_Run_After=upx.exe --best "%out%"
    #AutoIt3Wrapper_Run_After=del /f /q "Explosions (from AutoIteroids)_Obfuscated.au3"
    #include <GuiConstantsEx.au3>
    #include <GDIPlus.au3>
    #include <Array.au3>

    Opt('MustDeclareVars', 1)
    Global $hGUI, $hWnd, $hGraphic, $width, $height
    $width = @DesktopWidth * 0.75
    $height = @DesktopHeight * 0.75
    Global Const $explosion_step = 6, $explosion_length = ($width + $height) / 8, $explosion_max_amount = 20, $explosion_max_particle = 20
    Global $explosion_coordinate[$explosion_max_particle][6 * $explosion_max_amount] ; on/off, x, y, vx, vy, v
    Global $explosion_amount = 0
    ; Create GUI
    $hGUI = GUICreate("Explosions (from AUTOITEROIDS) using GDI+ by UEZ 2009!", $width, $height)
    $hWnd = WinGetHandle($hGUI)
    _GDIPlus_Startup()
    Global $graphics = _GDIPlus_GraphicsCreateFromHWND($hwnd)
    Global $bitmap = _GDIPlus_BitmapCreateFromGraphics($width, $height, $graphics)
    Global $backbuffer = _GDIPlus_ImageGetGraphicsContext($bitmap)
    _GDIPlus_GraphicsClear($backbuffer)
    _GDIPlus_GraphicsSetSmoothingMode($backbuffer, 4)
    Global $pen_size = 1
    Global $pen_color = 0xAFFF8070
    Global $pen = _GDIPlus_PenCreate($pen_color, $pen_size)
    GUISetState()

    Do
    _GDIPlus_GraphicsClear($backbuffer, 0x9A000000)
    If Mod(Random(1, 10, 1), 9) >= 5 Then ;
    Explosion_Init(Random(50, $width - 50, 1), Random(50, $height - 50, 1))
    EndIf
    Explosion()
    _GDIPlus_GraphicsDrawImageRect($graphics, $bitmap, 0, 0, $width, $height)
    Until Not Sleep(30) Or GUIGetMsg() = $GUI_EVENT_CLOSE

    ; Clean up resources
    _GDIPlus_PenDispose($pen)
    _GDIPlus_BitmapDispose($bitmap)
    _GDIPlus_GraphicsDispose($graphics)
    _GDIPlus_GraphicsDispose($backbuffer)
    _GDIPlus_Shutdown()


    Func Explosion_Init($ex, $ey) ;initialise explosion
    For $o = 0 To $explosion_step * ($explosion_max_amount - 1) Step $explosion_step ;fill array with coordinate of hit object
    If $explosion_coordinate[0][$o] <> 1 Then
    $explosion_coordinate[0][$o] = 1
    $explosion_coordinate[0][$o + 1] = $ex ;save x coordinate
    $explosion_coordinate[0][$o + 2] = $ey ;save x coordinate
    For $n = 0 To $explosion_max_particle - 1
    $explosion_coordinate[$n][$o + 1] = $explosion_coordinate[0][$o + 1] ;duplicate x start position of all explosion particles
    $explosion_coordinate[$n][$o + 2] = $explosion_coordinate[0][$o + 2] ;duplicate y start position of all explosion particles
    $explosion_coordinate[$n][$o + 3] = _Random(-7, 7, 1) ;create random x vector (explosion particle speed)
    $explosion_coordinate[$n][$o + 4] = _Random(-7, 7, 1) ;create random y vector (explosion particle speed)
    $explosion_coordinate[$n][$o + 5] = Abs($explosion_coordinate[$n][3 + $o]) + Abs($explosion_coordinate[$n][4 + $o]) ;add absolute distance of vectors x and y
    Next
    ExitLoop
    EndIf
    Next
    EndFunc ;==>Explosion_Init

    Func Explosion() ;draw explosions coordinates
    Local $q, $k
    $explosion_amount = 0
    For $k = 0 To $explosion_step * ($explosion_max_amount - 1) Step $explosion_step
    If $explosion_coordinate[0][$k] = 1 Then ;only draw active explosions
    $explosion_amount += 1
    For $q = 0 To $explosion_max_particle - 1
    $explosion_coordinate[$q][$k + 1] += $explosion_coordinate[$q][$k + 3] ;draw new x coordinate of a particle
    $explosion_coordinate[$q][$k + 2] += $explosion_coordinate[$q][$k + 4] ;draw new y coordinate of a particle
    $explosion_coordinate[$q][$k + 5] += Abs($explosion_coordinate[$q][$k + 3]) + Abs($explosion_coordinate[$q][$k + 4])
    If $explosion_coordinate[$q][$k + 5] <= $explosion_length Then ;draw until max. distance has been reached
    _GDIPlus_GraphicsDrawEllipse($backbuffer, $explosion_coordinate[$q][$k + 1], $explosion_coordinate[$q][$k + 2], 2, 2, $pen)
    Else ;when max. distance has been reached then set x vector and y vector to 0
    $explosion_coordinate[0][$k] = 0
    EndIf
    Next
    EndIf
    Next
    ConsoleWrite($explosion_amount & @CRLF)
    EndFunc ;==>Explosion

    Func _Random($w1, $w2, $w3 = 0) ;just to avoid 0 as random number
    Local $x = 0, $l1 = 0.50
    While $x = 0
    $x = Random($w1, $w2, $w3)
    If $x < $l1 And $x >= 0 Then $x += $l1
    If $x > -$l1 And $x <= 0 Then $x -= $l1
    WEnd
    Return $x
    EndFunc ;==>_Random

    Kann sich jemand vorstellen, warum das so ist?

    Gruß,
    UEZ

    PS: wie kann ich die Anzahl der Downloads von Anhängen (s.o.) darstellen? ?(

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    4 Mal editiert, zuletzt von UEZ (3. Juli 2009 um 21:18)

  • Die schlechte Performance kann ich bestätigen. Mein System: WinXP, AMD X4 940, ATI HD3870


    Den Anhang nicht in den Beitrag einfügen, sondern nur als Anhang stehen lassen.

    Danke für die Info -hab' mir einen Wolf gesucht...

    Zurück zum Problem. Vielleicht hängt es ja an WinXP, denn du benutzt ja eine ATI Karte.
    Auf meinen beiden Notebooks läuft Vista x32. Auf dem einen Notebook ist sogar auch eine nVidia Karte (NVS 140M).

    Merkwürdig!

    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Also bei mir läuft es flüssig (win XP,AMD Athlon X2 [4X3 GHZ] ,nVidia 8600GT )

    Aber es verbraucht verdammt viele recorsen :|


    Ach ja kommt der Thread nich ins Forum Off-Topic ?

  • Also bei mir läuft es flüssig (win XP,AMD Athlon X2 [4X3 GHZ] ,nVidia 8600GT )

    Aber es verbraucht verdammt viele recorsen :|


    Ach ja kommt der Thread nich ins Forum Off-Topic ?

    Du kannst an der Performance Schraube drehen, in dem du die Werte
    $explosion_max_amount = 20, $explosion_max_particle = 20 herab setzt.

    Wenn der Thread besser ins Off-Topic passt, dann ab dort hin damit.

    Mmmhhh, also WinXP kann also auch nicht das Problem sein! Sehr merkwürdig ?(

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    • Offizieller Beitrag

    Hallo

    Sehr sehr stockig mit:
    Win XP SP3
    Q6600 @ 3.2ghz
    GTX 280
    4gig Ram

    Mhh.. Aber ich denke weniger das GDI+ direkt von der GPU gerendert wird als mehr vom CPU.
    Trotzdem dürfte das bei einem 3ghz PC nicht passieren ;)
    Ich such mal ein bisschen im Code rum

    Mfg Spider

    Edit: Ah, bin Fündig geworden.
    Funktioniert das so bei dir besser (siehe Anhang)?

  • Wenn man den Befehl _GDIPlus_GraphicsClear($backbuffer, 0x9A000000) in der Do-Schleife auskommentiert läuft es deutlich schneller, kannst du den ersetzen?

    Edit: GTA Spider war schneller...

    • Offizieller Beitrag

    Hallo

    Genau das hab ich auch rausgefunden.
    Das ding ist, wenn man das Teil auskommentiert bleiben die Sprites am leben.
    Das sieht nicht schön aus und ist auch nicht Performancefördernd ;)
    _GDIPlus_GraphicsClear($backbuffer, 0x9A000000) --> _GDIPlus_GraphicsClear($backbuffer, 0xFF000000) allerdings funktioniert einwandfrei :)

    Mfg Spider

  • Krass, liegt wirklich am Alphachannel!

    Aber wieso läuft das Ding "flüssig" auf meinen beiden Notebooks (Vista x32) mit Alphachannel -> 9A :?:

    Ist mir eigentlich nur per Zufall aufgefallen, da ich selten an der Kiste hocke - eigentlich nur zum Zocken und das auch nur ab und wann! :D

    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    • Offizieller Beitrag

    Hallo

    Ja, tatsächlich komisch. Scheint wieder einer der typischen AutoIt Bugs zu sein.
    Irgendwo gibt es auch noch ein Memleck (habs grade mal 10 Minunten laufen lassen und er ist linear von 15mb RAM auf 19mb RAM hochgeklettert.)
    Wenn ich morgen nochmal Zeit finde schau ich noch mal drüber. Aber jetzt erstmal.. Kieler Woche :)

    Mfg Spider

    • Offizieller Beitrag

    Ich habe noch etwas merkwürdiges herausgefunden. Wenn ich Dein (UEZ) unverändertes Script nehme und starte, dann läuft es ja erstmal wie in Zeitlupe.
    Lasse ich es weiter laufen und klicke ein anderes Fenster (bei mir ist nebenbei die AutoIt-Hilfe offen) auf der Titelleiste an und halte die linke Maustaste fest, dann werden die Explosionen plötzlich richtig schnell angezeigt.
    Wenn ich die Maustaste dann wieder loslasse, sind die Explosionen wieder in Zeitlupe.

  • Ich habe noch etwas merkwürdiges herausgefunden. Wenn ich Dein (UEZ) unverändertes Script nehme und starte, dann läuft es ja erstmal wie in Zeitlupe.
    Lasse ich es weiter laufen und klicke ein anderes Fenster (bei mir ist nebenbei die AutoIt-Hilfe offen) auf der Titelleiste an und halte die linke Maustaste fest, dann werden die Explosionen plötzlich richtig schnell angezeigt.
    Wenn ich die Maustaste dann wieder loslasse, sind die Explosionen wieder in Zeitlupe.

    Stimmt! Vielleicht wirklich ein Bug!

    Wie läuft eigentlich GDI+ z.B. aus VB mit Alphachannel? Auch so langsam?

    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Hi,
    statt

    [autoit]

    _GDIPlus_GraphicsClear($backbuffer, 0x9A000000)

    [/autoit]


    mal die farbe auskommentieren

    [autoit]

    _GDIPlus_GraphicsClear($backbuffer)

    [/autoit]


    und es "brummt"

    *edit* blöd, wenn man erst nach über ner stunde das posting abschickt....längst gelöst...sry

  • Das ist schon klar, aber was ist, wenn man eine Alpha Blendeffekt haben möchte? Manche Effekte kommen mit dem Alpha Channel erst richtig rüber!
    Schau' mal hier: Butterfly Curve! Wenn du in Zeile 46 z.B. den Wert von 0x0F000000 auf 0xFF000000) setzt, dann "brummt"'s, aber der ursprungliche Effekt ist weg!

    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Ich würde auf einen Fehler in der GDI+ Datei in Windows XP tippen bzw in den DLLs die für das Zeichnen von Fenstern verantwortlich sind. Der "Trick" mit der Maustaste von Oscar funktioniert auch beim Butterfly-Beispiel. Es fängt exakt in dem Moment wo der Verschieberahmen auftaucht an, schnell zu laufen.

    Würde auch erklären warum es unter Vista funzt.

  • Zitat

    Ich würde auf einen Fehler in der GDI+ Datei in Windows XP tippen


    Habe es mit einem Win7, laufend in einer Virtualbox getestet, funzt einwandfrei.Seltsam, dass es bisher noch keinem aufgefallen ist.


  • Habe es mit einem Win7, laufend in einer Virtualbox getestet, funzt einwandfrei.Seltsam, dass es bisher noch keinem aufgefallen ist.

    Mir ist es im Prinzip schon vor längerem aufgefallen (seit den GDI+ Codes), aber habe mir keine so großen Gedanken gemacht. Heute wollte ich mal nachfragen, woran es liegen kann!

    Liegt wohl am Alpha Channel unter WinXP. Warum? Das ist noch zu klären.

    Habe im Developer Chat mal einen Topic dazu aufgemacht. Mal sehen, was die Entwickler sagen!

    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Wie wäre es denn damit?

    Hab 3 Zeilen geändert/Hinzugefügt Sind mit ;ÄNDERUNG !!!!! markiert.
    Läuft echt schnell. CPU AMD Athlon 1,25 GHz; 512 MB RAM; WinXP SP3

    Spoiler anzeigen
    [autoit]

    #AutoIt3Wrapper_Run_Obfuscator=y
    #Obfuscator_Parameters=/so
    #AutoIt3Wrapper_Res_SaveSource=n
    #AutoIt3Wrapper_UseUpx=n
    #AutoIt3Wrapper_Run_After=upx.exe --best "%out%"
    #AutoIt3Wrapper_Run_After=del /f /q "Explosions (from AutoIteroids)_Obfuscated.au3"
    #include <GuiConstantsEx.au3>
    #include <GDIPlus.au3>
    #include <Array.au3>

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

    Opt('MustDeclareVars', 1)
    Global $hGUI, $hWnd, $hGraphic, $width, $height
    $width = @DesktopWidth * 0.75
    $height = @DesktopHeight * 0.75
    Global Const $explosion_step = 6, $explosion_length = ($width + $height) / 8, $explosion_max_amount = 20, $explosion_max_particle = 20
    Global $explosion_coordinate[$explosion_max_particle][6 * $explosion_max_amount] ; on/off, x, y, vx, vy, v
    Global $explosion_amount = 0
    ; Create GUI
    $hGUI = GUICreate("Explosions (from AUTOITEROIDS) using GDI+ by UEZ 2009!", $width, $height)
    $hWnd = WinGetHandle($hGUI)
    _GDIPlus_Startup()
    Global $graphics = _GDIPlus_GraphicsCreateFromHWND($hwnd)
    Global $bitmap = _GDIPlus_BitmapCreateFromGraphics($width, $height, $graphics)
    Global $backbuffer = _GDIPlus_ImageGetGraphicsContext($bitmap)
    _GDIPlus_GraphicsClear($backbuffer)
    _GDIPlus_GraphicsSetSmoothingMode($backbuffer, 4)
    Global $pen_size = 1
    Global $pen_color = 0xAFFF8070
    Global $pen = _GDIPlus_PenCreate($pen_color, $pen_size)
    Global $test = _GDIPlus_BrushCreateSolid(0x9A000000) ; ÄNDERUNG !!!!
    GUISetState()

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

    Do
    ;_GDIPlus_GraphicsClear($backbuffer, 0x9A000000)
    _GDIPlus_GraphicsFillRect ($backbuffer,0, 0, $width, $height,$test) ; ÄNDERUNG !!!!
    If Mod(Random(1, 10, 1), 9) >= 5 Then ;
    Explosion_Init(Random(50, $width - 50, 1), Random(50, $height - 50, 1))
    EndIf
    Explosion()
    _GDIPlus_GraphicsDrawImageRect($graphics, $bitmap, 0, 0, $width, $height)
    Until Not Sleep(30) Or GUIGetMsg() = $GUI_EVENT_CLOSE

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

    ; Clean up resources
    _GDIPlus_PenDispose($pen)
    _GDIPlus_BrushDispose($test) ; ÄNDERUNG !!!!
    _GDIPlus_BitmapDispose($bitmap)
    _GDIPlus_GraphicsDispose($graphics)
    _GDIPlus_GraphicsDispose($backbuffer)
    _GDIPlus_Shutdown()

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

    Func Explosion_Init($ex, $ey) ;initialise explosion
    For $o = 0 To $explosion_step * ($explosion_max_amount - 1) Step $explosion_step ;fill array with coordinate of hit object
    If $explosion_coordinate[0][$o] <> 1 Then
    $explosion_coordinate[0][$o] = 1
    $explosion_coordinate[0][$o + 1] = $ex ;save x coordinate
    $explosion_coordinate[0][$o + 2] = $ey ;save x coordinate
    For $n = 0 To $explosion_max_particle - 1
    $explosion_coordinate[$n][$o + 1] = $explosion_coordinate[0][$o + 1] ;duplicate x start position of all explosion particles
    $explosion_coordinate[$n][$o + 2] = $explosion_coordinate[0][$o + 2] ;duplicate y start position of all explosion particles
    $explosion_coordinate[$n][$o + 3] = _Random(-7, 7, 1) ;create random x vector (explosion particle speed)
    $explosion_coordinate[$n][$o + 4] = _Random(-7, 7, 1) ;create random y vector (explosion particle speed)
    $explosion_coordinate[$n][$o + 5] = Abs($explosion_coordinate[$n][3 + $o]) + Abs($explosion_coordinate[$n][4 + $o]) ;add absolute distance of vectors x and y
    Next
    ExitLoop
    EndIf
    Next
    EndFunc ;==>Explosion_Init

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

    Func Explosion() ;draw explosions coordinates
    Local $q, $k
    $explosion_amount = 0
    For $k = 0 To $explosion_step * ($explosion_max_amount - 1) Step $explosion_step
    If $explosion_coordinate[0][$k] = 1 Then ;only draw active explosions
    $explosion_amount += 1
    For $q = 0 To $explosion_max_particle - 1
    $explosion_coordinate[$q][$k + 1] += $explosion_coordinate[$q][$k + 3] ;draw new x coordinate of a particle
    $explosion_coordinate[$q][$k + 2] += $explosion_coordinate[$q][$k + 4] ;draw new y coordinate of a particle
    $explosion_coordinate[$q][$k + 5] += Abs($explosion_coordinate[$q][$k + 3]) + Abs($explosion_coordinate[$q][$k + 4])
    If $explosion_coordinate[$q][$k + 5] <= $explosion_length Then ;draw until max. distance has been reached
    _GDIPlus_GraphicsDrawEllipse($backbuffer, $explosion_coordinate[$q][$k + 1], $explosion_coordinate[$q][$k + 2], 2, 2, $pen)
    Else ;when max. distance has been reached then set x vector and y vector to 0
    $explosion_coordinate[0][$k] = 0
    EndIf
    Next
    EndIf
    Next
    ConsoleWrite($explosion_amount & @CRLF)
    EndFunc ;==>Explosion

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

    Func _Random($w1, $w2, $w3 = 0) ;just to avoid 0 as random number
    Local $x = 0, $l1 = 0.50
    While $x = 0
    $x = Random($w1, $w2, $w3)
    If $x < $l1 And $x >= 0 Then $x += $l1
    If $x > -$l1 And $x <= 0 Then $x -= $l1
    WEnd
    Return $x
    EndFunc ;==>_Random

    [/autoit]

    Edit:
    Fügt man diese beiden Zeilen in die Do-Schleife vor das IF ein dann gibts ein buntes Feuerwerk :)
    $pen_color = "0xAF" & Hex(Random (1,255,1),2) & Hex(Random (1,255,1),2) & Hex(Random (1,255,1),2)
    _GDIPlus_PenSetColor($pen, $pen_color)

    BUUUUUUUUUUUUUUUUUUUNNNNT !! :D

    2 Mal editiert, zuletzt von Bitboy (28. Juni 2009 um 16:31)

  • Nette Idee mit dem Workaround, aber es flimmert immer wieder mal kurz weiß auf!

    Wenn ich ein bißchen mehr Zeit finde, werde ich die Partikel individual färben, d.h. jedes Pixel bekommt seine eigene Farbe :P

    In meinem Kopf schwirrt schon seit längerem der Gedanke, ein Feuerwerk zu coden. Mal sehen, wann ich die Zeit dafür finde.

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯