Assembler UDF ?

  • Moin,

    Andy und ich haben in der letzten Zeit viel an Assemblerfunktionen herumgebastelt. Die Resultate schwankten von Super toll bis kaum brauchbar^^
    Vermutlich sind wir aber nicht die einzigen die gerne mal eine (kleine) Asm Funktion basteln. Oft läuft das was gebaut wird redundant, weil keiner von den Erfolgen der Anderen weiß.

    Wäre es sinnvoll eine Sammelstelle für scheinbar nur ganz speziell nutzbare Asm Codes zu erstellen ?

    Die Erfahrung (und Logik) zeigt: Schnell ist nur was speziell für das, wofür es benötigt wird, zugeschnitten ist. Eine Funktion die mehr kann als sie muss ist also immer suboptimal.

    Wenn genügend Funktionen zusammenfinden ist es aber möglich für jedes Problem eine (halbwegs) passende Funktion zu finden.
    Ein weiterer Vorteil wäre, dass man über fremde Codes mal drüberschauen kann und ggf Verbesserungen vornehmen kann. So können auch weniger begabte AsmFanatiker ihren Beitrag liefern. Mit etwas Glück versteht einer der besseren das Prinzip der Funktion und kann es ggf optimieren.

    Ich habe mal angefangen ein paar meiner Funktionen in eine halbwegs nutzbare Form zu bringen, sodass sie (nach einigen Tests) fehlerfrei laufen. (asm stürzt ja idr öfters ab als alles andere^^).

    Ziel ist nicht nur der Geschwindigkeitsvorteil, sondern auch der Spaß am Unmöglichen.
    Und ganz nebenbei kann man noch eine Menge über seinen Computer lernen und wie er arbeitet.

    Was haltet ihr von der Idee ?

    Inhalte


    Anhang:
    - MemoryDll.au3
    - FASM.au3
    - AssembleIt.au3
    - ASMGfx.au3 (mal ganz provisorisch zusammengebastelt)
    - Beispiel.au3 (Vergleich GDI(+) / ASM in einem aus Commander Keen bekannten Minispiel)

    Bisherige Funktionen:
    - StretchBlt ( Nur mit dem Zoomfaktor 2) - Skaliert ein Bild auf 2Fache Größe
    - FillRect ( Noch nicht komplett in ASM übersetzt. Kein SSE. langsamer als GDI+ ) - Füllt ein Rechteck mit nichttransparenter Farbe
    - SwapColors - Ersetzt eine Farbe in einem Bild durch eine andere (gut um Schrift zu färben)
    - ClearBitmap - Ersatz für GraphicsClear oder BitBlt mit BLACKNESS
    - MoveMemory - Ersatz für BitBlt wenn X = Y = 0 und beide Bilder gleich groß sind.

    asm.au3
    [autoit]


    #include <GDIPlus.au3>
    #include <AssembleIt.au3>

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

    ; Struct Array
    Global $___avOP[1]

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

    ; DLLs
    Global $___ASM_DLL_USER32, $___ASM_DLL_GDI32

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

    ; ASM Func Positions
    Global $___ASM_OP_StretchBlt_Zoom_2, $___ASM_OP_Fill_Rect, $___ASM_OP_Swap_Colors, $___ASM_OP_Clear_Bitmap, $___ASM_OP_Move_Memory

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

    #region - Public

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

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _ASM_Move_Memory
    ; Description ...: Kopiert einen Teil im RAM an eine andere Stelle.
    ; Syntax.........: _ASM_Move_Memory($Ptr_Ziel, $Ptr_Quelle, $iBytes)
    ; Parameters ....: $Ptr_Ziel - Position im Ram an die geschrieben werden soll
    ; $Ptr_Quelle - Position im Ram von der gelesen werden soll
    ; $iQBytes - Anzahl QBytes die kopiert werden sollen (1 QByte = 4 Byte = 32Bit)
    ; Return values .:
    ; Author ........: Mars
    ; Modified.......:
    ; Remarks .......: Der zu kopierende Speicher muss mindestens 37 Byte enthalten.
    ; Related .......:
    ; Link ..........:
    ; Example .......:
    ; ===============================================================================================================================
    Func _ASM_MoveMemory($Ptr_Ziel, $Ptr_Quelle, $iQBytes)
    DllCall($___ASM_DLL_USER32, 'ptr', 'CallWindowProcW', 'ptr', DllStructGetPtr($___avOP[$___ASM_OP_Move_Memory]), 'ptr', $Ptr_Ziel, 'ptr', $Ptr_Quelle, 'int', $iQBytes, 'int', 0)
    EndFunc

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

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _ASM_Clear_Bitmap
    ; Description ...: Füllt alle Pixel eines Bildes mit der angegebenen Farbe
    ; Syntax.........: _ASM_Clear_Bitmap($vImg, $iCol)
    ; Parameters ....: $vImg - DllStruct die ein Bild incl Zusatzdaten enthält (_Image_Create...)
    ; $iCol - Farbe mit der alle Pixel gefärbt werden sollen
    ; Return values .:
    ; Author ........: Mars
    ; Modified.......:
    ; Remarks .......: Das zu clearende Bild muss mindestens 17 Pixel enthalten.
    ; Related .......:
    ; Link ..........:
    ; Example .......:
    ; ===============================================================================================================================
    Func _ASM_ClearBitmap($vImg, $iCol)
    DllCall($___ASM_DLL_USER32, 'ptr', 'CallWindowProcW', 'ptr', DllStructGetPtr($___avOP[$___ASM_OP_Clear_Bitmap]), 'ptr', DllStructGetData($vImg, 1, 4), 'ptr', DllStructGetData($vImg, 1, 2)*DllStructGetData($vImg, 1, 3), 'int', $iCol, 'int', 0)
    EndFunc

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

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _ASM_Swap_Colors
    ; Description ...: Ersetzt die gesuchte Farbe durch eine beliebige andere. (Transparenz wird unterstützt)
    ; Syntax.........: _ASM_Swap_Colors($vImg, $iCol1, $iCol2)
    ; Parameters ....: $vImg - DllStruct die ein Bild incl Zusatzdaten enthält (_Image_Create...)
    ; $iCol1 - Farbe die ersetzt werden soll
    ; $iCol2 - Farbe mit der ersetzt wird
    ; Return values .:
    ; Author ........: Mars
    ; Modified.......:
    ; Remarks .......:
    ; Related .......:
    ; Link ..........:
    ; Example .......:
    ; ===============================================================================================================================
    Func _ASM_SwapColors($vImg, $iCol1, $iCol2)
    DllCall($___ASM_DLL_USER32, 'ptr', 'CallWindowProcW', 'ptr', DllStructGetPtr($___avOP[$___ASM_OP_Swap_Colors]), 'ptr', DllStructGetData($vImg, 1, 4), 'ptr', $iCol1, 'int', $iCol2, 'int', DllStructGetData($vImg, 1, 2)*DllStructGetData($vImg, 1, 3))
    EndFunc

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

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _ASM_Fill_Rect
    ; Description ...: Füllt ein Rechteck auf dem Zielbild mit der angegebenen Farbe. Transparenz wird nicht unterstützt.
    ; Syntax.........: _ASM_Fill_Rect($vImg_Dest, $iX, $iY, $iW, $iH, $iCol)
    ; Parameters ....: $vImg_Dest - DllStruct die ein Bild incl Zusatzdaten enthält (_Image_Create...)
    ; $iX - x Koordinate der oberen Linken Ecke des Vierecks
    ; $iY - y Koordinate der oberen Linken Ecke des Vierecks
    ; $iW - Breite des Vierecks
    ; $iH - Höhe des Vierecks
    ; $iCol - Farbe des Rechtecks in 0xAARRGGBB Format. (Transparenz wird nur mit angegeben um im 32Bit Format zu bleiben)
    ; Return values .:
    ; Author ........: Mars
    ; Modified.......:
    ; Remarks .......: Die Funktion ist noch unvollständig in ASM übersetzt worden.
    ; Einige Berechnungen werden also noch in AutoIt durchgeführt.
    ; Related .......:
    ; Link ..........:
    ; Example .......:
    ; ===============================================================================================================================
    Func _ASM_FillRect($vImg_Dest, $iX, $iY, $iW, $iH, $iCol)

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

    Local $iMaxW = DllStructGetData($vImg_Dest, 1, 2) ; Breite des Zielbildes
    Local $iMaxH = DllStructGetData($vImg_Dest, 1, 3) ; Höhe des Zielbildes

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

    ; Situation:
    ; X und Y Koordinaten können überall, auch außerhalb liegen
    ; Breite und Höhe sind eventuell kleiner als 0.
    ; Das Rechteck passt eventuell nicht vollständig auf das Zielbild.
    ; --> Es wird nur ein Ausschnitt des Rechtecks gezeichnet.

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

    If $iX >= $iMaxW Then Return ; X liegt rechts neben dem Bild - Rechteck in jedem Fall außerhalb
    If $iY >= $iMaxH Then Return ; Y liegt unter dem Bild - Rechteck in jedem Fall außerhalb

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

    If $iX < 0 Then ; X liegt links neben dem Bild
    $iW -= Abs($iX) ; Rechteck eventuell innerhalb
    If $iW <= 0 Then Return ; Das Bild lag zu weit links...
    $iX = 0
    EndIf
    If $iY < 0 Then ; Y liegt über dem Bild
    $iH -= Abs($iH) ; Rechteck eventuell innterhalb
    If $iH <= 0 Then Return ; Das Bild lag zu weit oben...
    $iY = 0
    EndIf

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

    ; Jetzt sind X und Y innerhalb des Bildes und W und H größer 0
    ; Ist das Rechteck denn auch Passend ?
    ; Wenn nicht --> Zuschneiden !

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

    If $iW+$iX > $iMaxW Then $iW = $iMaxW - $iX ; Zu breit
    If $iH+$iY > $iMaxH Then $iH = $iMaxH - $iY ; Zu hoch

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

    If $iW <= 0 Then Return
    If $iH <= 0 Then Return

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

    Local Static $vStruct = DllStructCreate('int[7]') ; Parameter für den ASM Code
    DllStructSetData($vStruct, 1, $iX, 1) ; X
    DllStructSetData($vStruct, 1, $iY, 2) ; Y
    DllStructSetData($vStruct, 1, $iW, 3) ; W
    DllStructSetData($vStruct, 1, $iH, 4) ; H
    DllStructSetData($vStruct, 1, $iMaxW, 5) ; Bildbreite
    ;~ DllStructSetData($vStruct, 1, $iMaxH, 6) ; Bildhöhe
    DllStructSetData($vStruct, 1, $iCol, 6) ; Farbe

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

    DllCall($___ASM_DLL_USER32, 'ptr', 'CallWindowProcW', 'ptr', DllStructGetPtr($___avOP[$___ASM_OP_Fill_Rect]), 'ptr', DllStructGetData($vImg_Dest, 1, 4), 'ptr', DllStructGetPtr($vStruct), 'int', 0, 'int', 0)

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

    EndFunc

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

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _ASM_StretchBlt_Zoom_2
    ; Description ...: Vergrößert das Quellbild um den Faktor 2 und bildet es auf das Zielbild ab.
    ; Syntax.........: _ASM_StretchBlt_Zoom_2($vImg_Dest, $vImg_Source)
    ; Parameters ....: $vImg_Dest - DllStruct die ein Bild incl Zusatzdaten enthält (_Image_Create...)
    ; $vImg_Source - DllStruct die ein Bild incl Zusatzdaten enthält (_Image_Create...)
    ; Return values .:
    ; Author ........: Mars
    ; Modified.......:
    ; Remarks .......: Das Zielbild muss exakt die doppelte Breite, sowie die doppelte Höhe des Quellbildes besitzen.
    ; Der Interpolationsmodus ist Nearest Neighbour
    ; Related .......:
    ; Link ..........:
    ; Example .......:
    ; ===============================================================================================================================
    Func _ASM_StretchBlt_Zoom2($vImg_Dest, $vImg_Source)
    DllCall($___ASM_DLL_USER32, 'ptr', 'CallWindowProcW', 'ptr', DllStructGetPtr($___avOP[$___ASM_OP_StretchBlt_Zoom_2]), 'ptr', DllStructGetData($vImg_Dest, 1, 4), 'ptr', DllStructGetData($vImg_Source, 1, 4), 'int', DllStructGetData($vImg_Source, 1, 2), 'int', DllStructGetData($vImg_Source, 1, 3))
    EndFunc

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

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _ASM_Startup
    ; Description ...: Läd nötige DLLs und initialisiert alle OP-Codes für die spätere Benutzung.
    ; Syntax.........: _ASM_Startup()
    ; Parameters ....:
    ; Return values .:
    ; Author ........: Mars
    ; Modified.......:
    ; Remarks .......:
    ; Related .......: _ASM_Shutdown
    ; Link ..........:
    ; Example .......:
    ; ===============================================================================================================================
    Func _ASM_Startup()

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

    ; Erstmal ein Reset
    FasmReset($Fasm)

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

    ; DLLs starten
    $___ASM_DLL_USER32 = DllOpen('USER32.DLL')
    $___ASM_DLL_GDI32 = DllOpen('GDI32.DLL')

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

    ; Jede Funktion kann nach dem Schema eingefügt werden.
    ; Alle ASM Codes werden als Struct in einem Array gelagert.

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

    $___ASM_OP_StretchBlt_Zoom_2 = __ASM_Add_OP(__ASM_Stretch_Zoom_2())
    $___ASM_OP_Fill_Rect = __ASM_Add_OP(__ASM_Fill_Rect())
    $___ASM_OP_Swap_Colors = __ASM_Add_OP(__ASM_Swap_Colors())
    $___ASM_OP_Clear_Bitmap = __ASM_Add_OP(__ASM_Clear_Bitmap())
    $___ASM_OP_Move_Memory = __ASM_Add_OP(__ASM_Move_Memory())

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

    EndFunc

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

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _ASM_Shutdown
    ; Description ...: Gibt die Ressourcen wieder frei.
    ; Syntax.........: _ASM_Shutdown()
    ; Parameters ....:
    ; Return values .:
    ; Author ........: Mars
    ; Modified.......:
    ; Remarks .......:
    ; Related .......: _ASM_Startup
    ; Link ..........:
    ; Example .......:
    ; ===============================================================================================================================
    Func _ASM_Shutdown()

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

    ; Structs leeren
    For $i = 1 To $___avOP[0] Step 1
    $___avOP[$i] = 0
    Next

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

    ; DLLs schließen
    DllClose($___ASM_DLL_USER32)

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

    EndFunc

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

    #endregion - Public

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

    #region - Internal

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

    ; #INTERNAL_USE_ONLY# ===========================================================================================================
    ; Name...........: __ASM_Add_OP
    ; Description ...: Fügt OP-Codes zum Struct Array hinzu
    ; Syntax.........: __ASM_Add_OP($a)
    ; Parameters ....: $a - Dieser Parameter ermöglicht das kompakte Aufrufen der ASM Funktion die hinzugefügt werden soll.
    ; Return values .: Aktueller OP-Index. (Zufriff auf ASM Ops über diesen Index möglich)
    ; Author ........: Mars
    ; Modified.......:
    ; Remarks .......:
    ; Related .......:
    ; Link ..........:
    ; Example .......:
    ; ===============================================================================================================================
    Func __ASM_Add_OP($a)
    Local $vOP = __ASM_GetStruct()
    Local $u = UBound($___avOP)
    ReDim $___avOP[$u+1]
    $___avOP[0] += 1
    $___avOP[$u] = $vOP
    Return $___avOP[0]
    EndFunc

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

    ; #INTERNAL_USE_ONLY# ===========================================================================================================
    ; Name...........: __ASM_GetStruct
    ; Description ...: Verpackt den in Fasm befindlichen Code in eine DllStruct die per CallWindowProc aufgerufen werden kann.
    ; Syntax.........: __ASM_GetStruct()
    ; Parameters ....:
    ; Return values .: $vStruct - Die DllStruct beinhaltet den ASM-Code
    ; Author ........: Mars
    ; Modified.......:
    ; Remarks .......:
    ; Related .......:
    ; Link ..........:
    ; Example .......:
    ; ===============================================================================================================================
    Func __ASM_GetStruct()
    Local $vStruct = __ASM_ToStruct(FasmGetBinary($Fasm))
    FasmReset($Fasm)
    Return $vStruct
    EndFunc ;==>_Get_ASM_Struct

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

    ; #INTERNAL_USE_ONLY# ===========================================================================================================
    ; Name...........: __ASM_ToStruct
    ; Description ...: Verpackt den im Parameter enthaltenen Code in eine DLLStruct
    ; Syntax.........: __ASM_ToStruct($ASM)
    ; Parameters ....: $ASM - ASM Code
    ; Return values .: $vStr - Die DllStruct beinhaltet den Code aus $ASM
    ; Author ........: Mars
    ; Modified.......:
    ; Remarks .......:
    ; Related .......:
    ; Link ..........:
    ; Example .......:
    ; ===============================================================================================================================
    Func __ASM_ToStruct($ASM)
    Local $vStr = DllStructCreate('byte[' & StringLen($ASM) / 2 - 1 & ']')
    DllStructSetData($vStr, 1, $ASM)
    Return $vStr
    EndFunc ;==>_AsmToStruct

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

    #endregion - Internal

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

    #region - ASM

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

    Func __ASM_Move_Memory()
    _('use32')
    _('mov edi, [esp+4]') ; Ptr Ziel
    _('mov esi, [esp+8]') ; Ptr Quelle
    _('mov ecx, [esp+12]') ; Anzahl Pixel
    _('mov eax, edi') ;
    _('sub eax, esi') ; eax = Abstand Ziel und Quellbitmap im Ram
    _('sub ecx, 32') ; 32 Px schritte
    _('align 16')
    _('_px32:') ; 32Px - Schleife
    _('movdqa xmm0, [esi]')
    _('movdqa xmm1, [esi+16]')
    _('movdqa xmm2, [esi+32]')
    _('movdqa xmm3, [esi+48]')
    _('movdqa xmm4, [esi+64]')
    _('movdqa xmm5, [esi+80]')
    _('movdqa xmm6, [esi+96]')
    _('movdqa xmm7, [esi+112]')
    _('movdqa [esi+eax], xmm0')
    _('movdqa [esi+eax+16], xmm1')
    _('movdqa [esi+eax+32], xmm2')
    _('movdqa [esi+eax+48], xmm3')
    _('movdqa [esi+eax+64], xmm4')
    _('movdqa [esi+eax+80], xmm5')
    _('movdqa [esi+eax+96], xmm6')
    _('movdqa [esi+eax+112], xmm7')
    _('add esi, 128')
    _('sub ecx, 32')
    _('ja _px32')
    _('add ecx, 28') ; add 32 und sub 4
    _('_px4:') ; 4px Schleife
    _('movdqa xmm0, [esi]')
    _('movdqa [esi+eax], xmm0')
    _('add esi, 16')
    _('sub ecx, 4')
    _('ja _px4')
    _('add ecx, 4')
    _('_px1:') ; 1px Schleife
    _('mov ebx, [esi]')
    _('mov [esi+eax], ebx')
    _('add esi, 4')
    _('dec ecx')
    _('ja _px1')
    _('ret')
    EndFunc ;==>__ASM_Move_Memory

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

    Func __ASM_Clear_Bitmap()
    _('use32')
    _('mov edi, [esp+4]') ; ptr
    _('mov ebx, [esp+12]') ; col
    _('mov ecx, [esp+8]') ; px
    _('movd xmm0,ebx') ; xmm0 = col
    _('punpckldq xmm0,xmm0') ; xmm0 = col|col
    _('punpckldq xmm0,xmm0') ; xmm0 = col|col|col|col
    _('sub ecx, 32') ; 32px weniger füllen (ermöglicht beliebige Breite und Höhe trotz SSE) Die Grafik muss aber mindestens 16(+1)px besitzen. Sonst schlägt der clear fehl.
    _('_Schleife:')
    _('movdqa [edi], xmm0')
    _('movdqa [edi+16], xmm0')
    _('movdqa [edi+32], xmm0')
    _('movdqa [edi+48], xmm0')
    _('movdqa [edi+64], xmm0')
    _('movdqa [edi+80], xmm0')
    _('movdqa [edi+96], xmm0')
    _('movdqa [edi+112], xmm0')
    _('add edi,128')
    _('sub ecx, 32') ; 16px Schritte
    _('ja _Schleife')
    _('add ecx, 28')
    _('_px4:') ; 4px Schleife
    _('movdqa [edi], xmm0')
    _('add edi, 16')
    _('sub ecx, 4')
    _('ja _px4')
    _('add ecx, 4')
    _('_px:') ; die letzten maximal 16 Pixel füllen
    _('mov [edi], ebx')
    _('add edi, 4')
    _('dec ecx') ; 1px Schritte
    _('ja _px')
    _('ret ')
    EndFunc

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

    Func __ASM_Swap_Colors()
    _('use32')
    _('mov edi, [esp+4]') ; Bitmap
    _('mov ebx, [esp+8]') ; Suchfarbe
    _('mov edx, [esp+12]') ; ersetzfarbe
    _('mov ecx, [esp+16]') ; anzahl Pixel
    _('_Px:')
    _('cmp [edi], ebx') ; Zielfarbe gefunden ?
    _('jne _weiter') ; neee dann weiter
    _('mov [edi], edx') ; jaaa dann ersetzen !
    _('_weiter:') ; weiter
    _('add edi, 4') ; 1px nach vorne
    _('dec ecx')
    _('jnz _Px')
    _('ret')
    EndFunc

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

    Func __ASM_Fill_Rect()
    _('use32')
    _('mov esi, [esp+4]') ; ptr - Zielbitmap
    _('mov edx, [esp+8]') ; ptr - Datenstruct
    _('mov edi, [edx]') ; edi = X
    _('mov ecx, [edx+4]') ; ecx = Y
    _('mov ebx, [edx+8]') ; Viereck Breite
    _('movd xmm0, [edx+12]') ; Viereck Höhe
    _('mov eax, [edx+16]') ; Bild Breite
    _('movd xmm1, [edx+20]') ; Farbe
    _('imul ecx, eax') ; Y * Bildbreite
    _('add edi, ecx')
    _('shl edi, 2')
    _('add edi, esi') ; edi = Pixelpos
    _('shl eax, 2') ; eax = Anzahl Bytes in einer Reihe des Ziels
    _('shl ebx, 2') ; ebx = Anzahl Bytes in einer Reihe des Vierecks
    _('sub eax, ebx') ; eax = Differenz zwischen dem letzten px einer Reihe und dem ersten der Nächsten.
    _('shr ebx, 2') ; ebx = Anzahl Px in einer Reihe
    _('movd esi, xmm1')
    _('movd ecx, xmm0') ; ecx = Reihen die abgearbeitet werden müssen !
    _('_X:')
    _('push ecx') ; ecx = verbleibende Reihen.
    _('mov ecx, ebx') ; ecx wieder auf Viereckbreite setzen
    _('_Y:') ; innerer Loop (kleiner gehts nicht...)
    _('mov dword[edi], esi')
    _('add edi, 4')
    _('dec ecx')
    _('jnz _Y')
    _('add edi, eax') ; eine Reihe nach unten
    _('pop ecx')
    _('dec ecx')
    _('jnz _X')
    _('ret')
    EndFunc

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

    Func __ASM_Stretch_Zoom_2()
    _('use32')
    _('mov edi, [esp+4]')
    _('mov esi, [esp+8]')
    _('mov eax, [esp+12]')
    _('mov ecx, [esp+16]')
    _('movd xmm0, eax')
    _('shl eax, 3')
    _('movd xmm2, eax')
    _('_Y:')
    _('mov eax, ecx')
    _('push ecx')
    _('movd ecx, xmm0')
    _('_X:')
    _('push eax')
    _('mov ebx, ecx')
    _('dec eax')
    _('dec ebx')
    _('push eax')
    _('movd xmm3, ecx') ; ecx sichern (push/pop geht nicht hier)
    _('movd ecx, xmm0') ; ecx =breite
    _('imul eax, ecx') ; Mal Breite.
    _('add eax, ebx')
    _('shl eax, 2')
    _('movd xmm1, [eax+esi]') ; Farbe in xmm1 eax+esi = Pixelpos im Quellbild.
    _('punpckldq xmm1, xmm1') ; Farbe|Farbe
    _('pop edx')
    _('shl edx, 4')
    _('imul edx, ecx') ; Mal Breite
    _('movd ecx, xmm3') ; Ecx wieder herstellen
    _('shl ebx, 3')
    _('add edx, ebx')
    _('add edx, edi') ; Zielposition
    _('movq [edx], xmm1') ; 2 Px schreiben
    _('movd eax, xmm2') ; eax = Breite * 4 * 2px
    _('movq [edx+eax], xmm1') ; 2Px schreiben
    _('pop eax')
    _('dec ecx')
    _('jnz _X')
    _('pop ecx')
    _('dec ecx')
    _('jnz _Y')
    _('ret')
    EndFunc ;==>__ASM_Stretch_Z2

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

    #endregion - ASM

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

    #region - Teile der ImageUDF zum erstellen ASM kompatibeler Bilder

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

    ; #FUNCTION# ;===============================================================================
    ; Name...........: _Image_Create
    ; Description ...: Creates an empty Image
    ; Syntax.........: _Image_Create($iW, $iH)
    ; Parameters ....: $iW - Width of the image
    ; $iH - Height of the image
    ; Return values .: Dllstruct containing the image informations
    ; Author ........: Mars
    ; Modified.......:
    ; Remarks .......:
    ; Related .......: _Image_CreateFromFile, _Image_Delete
    ; Link ..........:
    ; Example .......:
    ; ===========================================================================================
    Func _Image_Create($iW, $iH)
    Local $Ptr, $hDC, $hBmp, $tBMI, $aDIB, $vStruct
    $hDC = _WinAPI_CreateCompatibleDC(0)
    $tBMI = DllStructCreate('struct;dword Size;long Width;long Height;word Planes;word BitCount;dword Compression;dword SizeImage;long XPelsPerMeter;long YPelsPerMeter;dword ClrUsed;dword ClrImportant;endstruct;dword RGBQuad')
    DllStructSetData($tBMI, 'Size', DllStructGetSize($tBMI) - 4)
    DllStructSetData($tBMI, 'Width', $iW)
    DllStructSetData($tBMI, 'Height', -$iH)
    DllStructSetData($tBMI, 'Planes', 1)
    DllStructSetData($tBMI, 'BitCount', 32)
    $aDIB = DllCall($___ASM_DLL_GDI32, '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]

    ; #FUNCTION# ;===============================================================================
    ; Name...........: _Image_CreateFromFile
    ; Description ...: Creates an Image from file
    ; Syntax.........: _Image_CreateFromFile($sPath)
    ; Parameters ....: $sPath - Path to image file
    ; Return values .: Dllstruct containing the image informations
    ; Author ........: Mars
    ; Modified.......:
    ; Remarks .......:
    ; Related .......: _Image_Create, _Image_Delete
    ; Link ..........:
    ; Example .......:
    ; ===========================================================================================
    Func _Image_CreateFromFile($sPath)
    Local $hImage = _GDIPlus_ImageLoadFromFile($sPath)
    Local $iW = _GDIPlus_ImageGetWidth($hImage)
    Local $iH = _GDIPlus_ImageGetHeight($hImage)
    Local $vImage = _Image_Create($iW, $iH)
    Local $hGraphic = _GDIPlus_GraphicsCreateFromHDC(DllStructGetData($vImage, 1, 1))
    _GDIPlus_GraphicsDrawImage($hGraphic, $hImage, 0, 0)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_GraphicsDispose($hGraphic)
    Return $vImage
    EndFunc ;==>_Image_CreateFromFile

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

    ; #FUNCTION# ;===============================================================================
    ; Name...........: _Image_Delete
    ; Description ...: Deletes an Image
    ; Syntax.........: _Image_Delete(ByRef $vStruct)
    ; Parameters ....: $vStruct - DllStruct returned by an Image_Create function
    ; Return values .: None
    ; Author ........: Mars
    ; Modified.......:
    ; Remarks .......:
    ; Related .......: _Image_Create, _Image_CreateFromFile
    ; Link ..........:
    ; Example .......:
    ; ===========================================================================================
    Func _Image_Delete(ByRef $vStruct)
    _WinAPI_DeleteObject(DllStructGetData($vStruct, 1, 5))
    _WinAPI_DeleteDC(DllStructGetData($vStruct, 1, 1))
    $vStruct = 0
    EndFunc ;==>_Image_Delete

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

    #endregion - Teile der ImageUDF

    [/autoit]


    Um Von GDI(+) auf ASM zu schalten muss in Zeile 8 das $UseASM auf False gesetzt werden.
    Es wird jetzt automatisch zwischen ASM und GDI(+) hin und her geschaltet und ein Mittel gebildet.
    Leider verspielt FillRect alle rausgeholten ms wieder, sodass ASM und GDI im Beispiel etwa gleich sein sollten.

    Bugfix - MoveMemory ließ das Programm beim Beenden abschmieren.

  • Klasse Sache - bin begeistert!

    Ich hoffe, dass es eine gute Sammlung an ASM Codes für GDI+ geben wird! :D

    Vielleicht kann ich auch was dazu beitragen!

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Hi,
    das Ziel sollte sein, bestehende GDI/GDI+-Scripte, welche an Performanceproblemen leiden, durch einfaches Ersetzen von ASM-UDF-Funktionen zu beschleunigen.
    Dazu ist es immens wichtig, zuerst den Grund der niedrigen Geschwindigkeit herauszufinden, d.h. die "langsame" Funktion zu suchen (profiling).
    Es nützt nichts, einen Bitblt, der nur eine Millisekunde benötigt, durch einen zu ersetzen, der dreimal so schnell ist! Jedenfalls nicht in 99% aller Fälle :D

    Reine GDI-Programme sind idR. unkritisch, es gibt verschiedenste Möglichkeiten, an den Pointer der Bitmapdaten (Pixel) zu kommen.
    Ich plädiere dafür, im Vorfeld nur Bitmaps zu erstellen, die bereits einen Pointer auf die "Pixel" enthalten.
    Die von mir in _CreateNewBmp32() gewrapperte Funktion CreateDIBSection() ist die eierlegende Wollmilchsau! Es wird eine leere Bitmap erstellt und HDC, Pointer auf die "Pixel" und ein per GDI(+ ?) -verwendbares "Handle" zurückgegeben.
    Dann die ASM-Funktion aufrufen, blitten, fertig.
    Da die gesammelten Asm-Funktionen in eine gemeinsame DLL sollen, sehe ich kein Problem.


    Bei GDI+ sieht die Sache schon anders aus!
    Greenhorn, UEZ und ich haben sich schon Nächte um die Ohren gehauen, um einen Weg zu finden um die Pointer auf die Bitmapdaten ("Pixel" RGBA) im Speicher zu lokalisieren bzw aus den bestehenden GDI(+)-Funktionen zu extrahieren.
    Ich habe dann eingeworfen, dass die Funktion BitmapLockBits() verhältnismässig langsam sei. Diese Aussage ist aber wohl nur auf nicht performanten Rechnern zu halten (wzbw).
    /EDIT/ Wobei ganz klar zu sagen ist, dass der "Lock" immer noch Faktor 20-30x langsamer ist (bzw. mehr Zeit kostet) als diverse ASM-Funktionen, welche die komplette Bitmap bearbeiten!

    Zzt. würde ich also dafür plädieren, dass die Assemblerfunktionen ihren Pointer aus der BitmapLockBits() erhalten.
    Somit wäre folgende Vorgehensweise bzw. Grundgerüst für die _GDIplus_Funktionsname_ASM() praktikabel:

    • Aus der Orginalfunktion das benötigte "Handle" identifizieren und in ein für BitmapLockBits() verwendbares Handle umwandeln
      BitmapLockBits()
      ASM-Code
      BitmapUnLockBits()


    Dann geht´s nun los^^
    Sammelt fleissig (schnellen) ASM-Code und/oder auch neue Ideen für zzt nicht oder nur langsam implementierte Funktionen, damit wir gemeinsam eine "richtige" UDF aufbauen können :thumbup:

    Zitat

    sodass sie (nach einigen Tests) fehlerfrei laufen. (asm stürzt ja idr öfters ab als alles andere).

    Bei Fehlern im Asm-Code gebe ich dir Recht da muss dann Gebugfixt werden!
    Fehler in der "Ansteuerung" allerdings würde ich gerne auf den Anwender (Programmierer) abwälzen wollen.
    Imho bringt es nichts (denn daran krankt u.a. die gesamte Win-API), eigendlich schnelle Funktionen mit einem "Ich fange jede fehlerhafte Eingabe ab"-Header zu versehen, um dann Code aus 1998 zu verwenden (ist in erheblichen Teilen in Win7 enthalten), nur weil sich damals jemand die Mühe gemacht hat, DAU-resistenten Code zu schreiben!

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    2 Mal editiert, zuletzt von Andy (20. Mai 2012 um 11:07)

  • Zitat von Andy

    bestehende GDI/GDI+-Scripte, welche an Performanceproblemen leiden, durch einfaches Ersetzen von ASM-UDF-Funktionen zu beschleunigen.
    Dazu ist es immens wichtig, zuerst den Grund der niedrigen Geschwindigkeit herauszufinden, d.h. die "langsame" Funktion zu suchen (profiling).
    Es nützt nichts, einen Bitblt, der nur eine Millisekunde benötigt, durch einen zu ersetzen, der dreimal so schnell ist! Jedenfalls nicht in 99% aller Fälle :D

    Zu den "schwierigen" Funktionen kommen wir schon noch.
    Im Beispiel ist ja der Clear mittels BitBlt WHITENESS oder BLACKNESS durch asm ersetzt.
    Bei Schwarz und Weiß ist der BitBlt im Vergleich nur ganz knapp langsamer. Bei anderen Farben kann der BitBlt aber nicht genutzt werden. Und bei _GDIPlus_CraphicsClear ist die ASM Func deutlich im Vorteil.
    Und der Clear war so einfach zu schreiben (inzwischen MIT SSE und dennoch beliebiger Breite und Höhe), dass er einfach sein musste^^

    Zitat von Andy

    Die von mir in _CreateNewBmp32() gewrapperte Funktion CreateDIBSection() ist die eierlegende Wollmilchsau! Es wird eine leere Bitmap erstellt und HDC, Pointer auf die "Pixel" und ein per GDI(+ ?) -verwendbares "Handle" zurückgegeben.
    Dann die ASM-Funktion aufrufen, blitten, fertig.

    Deine Funktion steckt im Image_Create mit drin. Weil sie mir relativ umständlich zu handhaben erschien. (relativ!). Man musste vorher Variablen für ptr, dc, usw erstellen und diese als Parameter übergeben. Das Prinzip ist nun, dass man nur noch Breite und Höhe angibt. Rückgabe ist eine Struct mit int[5] für hDC, Breite, Höhe, Ptr, HBMP. Man hat also keine unnötigen Variablen mehr, sondern nur noch eine Struct mit allen Daten zum Bild.

    Zusammen mit _GDIPlus_GraphicsCreateFromHDC ergibt sich ein Buffer den sowohl GDI+ ($hGFX), GDI ($hDC) und ASM ($ptr) nutzen können. (Im Beispiel ist das in Zeile 100 bis 110. Da wird beim gleichen Bitmap mit GDI+, GDI und ASM gemalt)

    Bei Bitmaps die direkt in GDI+ geladen wurden weiß ich leider auch keinen eleganten Ausweg um an irgendwelche Daten zu kommen...


    Edit: Gerade einen blöden Fehler entdeckt...
    Zeile 67 und 68 (der Timer) müssen in Zeile 99 verschoben werden.
    Sonst stoppt der Timer auch die Hälfte der AutoItberechnungen und sonstiges. Er soll ja NUR die ASM/GDI(+) Funktionen stoppen^^

  • Zusammen mit _GDIPlus_GraphicsCreateFromHDC ergibt sich ein Buffer den sowohl GDI+ ($hGFX), GDI ($hDC) und ASM ($ptr) nutzen können. (Im Beispiel ist das in Zeile 100 bis 110. Da wird beim gleichen Bitmap mit GDI+, GDI und ASM gemalt)

    Bei Bitmaps die direkt in GDI+ geladen wurden weiß ich leider auch keinen eleganten Ausweg um an irgendwelche Daten zu kommen...

    Genau hier für suchen wir eine Lösung, denn z.B. mit

    [autoit]


    _GDIPlus_GraphicsCreateFromHWND()

    [/autoit]

    kannst du direkt in den Grafikspeicher zeichnen, so dass du das Ergebnis sofort siehst. In den oben erwähnten Verfahren musst du noch mit _WinAPI_BitBlt() das Ergebnis sichtbar machen, sprich die Bitmap aus dem Speicher in den Grafikspeicher kopieren.

    Die Frage ist nun, gibt es auch in ASM ein möglichkeit direkt den Grafikspeicherbereich zu benutzen!

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Zitat

    Die Frage ist nun, gibt es auch in ASM ein möglichkeit direkt den Grafikspeicherbereich zu benutzen!

    Genau das ist der Knackpunkt!
    GDI+ "zaubert" ja nicht irgendwie die Bitmap in den Grafikkartenspeicher, das passiert ja auch über eine Art Bitblt...ergo MUSS die GDI+Bitmap (DDB) irgendwo im Speicher stehen. Leider lässt uns Windows nicht in diesen extra geschützten Speicherbereich :thumbdown:
    Man muss also diesen gesicherten Speicherbereich zugänglich machen (das passiert per BitmapLockBits) oder eine Kopie dieses Speicherbereichs anlegen (GetDIBits), leider ist beides schnarchlangsam .....GetDIBits/SetDIBits wg _GDIPlus_BitmapCreateHBITMAPFromBitmap()/_GDIPlus_BitmapCreateFromHBITMAP() braucht ca 1,5x länger als LockBits/UnLockBits

    Das Problem dabei ist, für JEDE Pixel-Manipulation ausserhalb der GDI+(DDB)-Funktionen jedes Mal die Bitmap zu kopieren, zu manipulieren und nachher wieder zurückzukopieren.
    Das alles hat man sich mit der Verwendung einer DIB gespart. Allerdings mit dem zugegebenermaßen bestehenden Nachteil, auf bestimmten Devices (Monochrom, 16Bit-Color, Plotter usw.) die 32Bit ARGB-Manipulation nicht immer mit dem gewünschten Ergebnis zu bekommen

  • Moin,

    Hab gerade eine Memory Move Funktion hinzugefügt. (auch als BitBlt nutzbar, wenn X und Y jeweils 0 sind und die Bilder gleich groß).

    Dabei ist mir etwas interessantes Aufgefallen: Das Ram mag es nicht, wenn man darin rumspringt.
    Ein Clear (selbst wenn man jeden px einzeln setzt) geht ja relativ flott. Daher dachte ich: Ein BitBlt dauert ca. 2x so lange, da ich statt einen Ram Zugriff pro Pixel zweie habe.

    Aber Pustekuchen. Der Spaß dauerte 5Mal so lange^^
    SSE konnte da natürlich abhilfe schaffen, weil man dann direkt 32Px gleichzeig liest und schreibt. Also muss man nur alle 32Px im Ram Springen. Das ist aber immernoch zu viel. Kann man vllt iwie größere Mengen Daten (schnell) in den Stack stopfen ? So z.B. 128 Px (512 Byte).
    Zeit für AVX. Damit gehen gepflegt 128 Pixel in die Register^^
    Zusammen mit nicht destruktiven Befehlen wird das bestimmt nochmal ca. 3x so schnell wie SSE.

    Und noch eine allgemeine Idee für Zeichengpässe (z.B. bei 1000 Vierecken, oder 1000 Linien oä).
    Da ist es wahrscheinlich sinnvoll eine ASM func zu haben die die Liste durchgeht, statt jedes Mal in AutoIt einen Call zu machen. Allein der dauert 0.05ms. Und bei z.B. 1000 Linien sind das allein fürs Aufrufen schon 50ms. Das ist bei flüssiger Darstellung unzumutbar. (Ich spiele hier auf das 3D Programm an was neulich gezeigt wurde mit den unmengen Linien).

  • Zitat von Marsi

    Da ist es wahrscheinlich sinnvoll eine ASM func zu haben die die Liste durchgeht, statt jedes Mal in AutoIt einen Call zu machen.

    daher vorher eine DIB erstellen und mit ASM-Funktionen bearbeiten und wie gehabt blitten. Allerdings fallen dann die "schönen" GDI+-Funktionen wie z.B. Path- und Matrixfunktionen hinten runter :huh: Denn der Weg von einer DIB zu einer DDB ist genauso langsam wie umgekehrt!

    Daher stellt sich immer mehr die Frage, WAS in einem GDI+-Programm eigendlich die Performance frisst! Das ist der Ansatzpunkt!

    Zitat

    SSE konnte da natürlich abhilfe schaffen, weil man dann direkt 32Px gleichzeig liest und schreibt. Also muss man nur alle 32Px im Ram Springen. Das ist aber immernoch zu viel. Kann man vllt iwie größere Mengen Daten (schnell) in den Stack stopfen ? So z.B. 128 Px (512 Byte).

    AVX bringt da nicht viel, da nur Speicherbewegungen stattfinden. Prefetching (Daten vorrausschauend in den Cache laden) hilft am meisten! Wenn der Cache voll mit den Daten ist, die bald benötigt werden, dann dauert ein MemMove statt 10-15 nur noch 2-3 Takte....
    In einer Schleife bringt das ca. 50% mehr Speed.

  • Ok.. Die Frage ist dann: wohin mit dem prefetch ?
    (wir benutzen prefetchnta oder ? Die Daten werden ja nur ein Mal gelesen).

    Habe es an mehreren Stellen getestet. Schneller als ganz ohne wurde das Resultat nicht. Eher langsamer.
    Und diese Verlangsamung hat das ganze Skript mit runtergezogen. Der GDI Teil war dann auch immer wesentlich langsamer als sonst.

    Spoiler anzeigen
    [autoit]

    Func __ASM_Move_Memory()
    _('use32')
    _('mov edi, [esp+4]') ; Ptr Ziel
    _('mov esi, [esp+8]') ; Ptr Quelle
    _('mov ecx, [esp+12]') ; Anzahl Pixel
    _('mov eax, edi') ;
    _('sub eax, esi') ; eax = Abstand Ziel und Quellbitmap im Ram
    _('sub ecx, 32') ; 32 Px schritte
    ;~ _('align 16')
    ;~ _('prefetch [esi+512]') ; ##################### Prefetch ?
    _('_px32:') ; 32Px - Schleife
    ;~ _('prefetchnta [esi+1024]')
    _('movdqa xmm1, [esi]')
    _('movdqa xmm2, [esi+16]')
    _('movdqa xmm3, [esi+32]')
    _('movdqa xmm4, [esi+48]')
    _('movdqa xmm5, [esi+64]')
    _('movdqa xmm6, [esi+80]')
    _('movdqa xmm7, [esi+96]')
    _('movdqa xmm0, [esi+112]')

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

    _('movdqa [esi+eax], xmm1')
    _('movdqa [esi+eax+16], xmm2')
    _('movdqa [esi+eax+32], xmm3')
    _('movdqa [esi+eax+48], xmm4')
    _('movdqa [esi+eax+64], xmm5')
    _('movdqa [esi+eax+80], xmm6')
    _('movdqa [esi+eax+96], xmm7')
    _('movdqa [esi+eax+112], xmm0')
    _('add esi, 128')
    _('sub ecx, 32')
    ;~ _('prefetchnta [esi+128]')
    _('ja _px32')
    _('add ecx, 28') ; add 32 und sub 4
    _('_px4:') ; 4px Schleife
    _('movdqa xmm0, [esi]')
    _('movdqa [esi+eax], xmm0')
    _('add esi, 16')
    _('sub ecx, 4')
    _('ja _px4')
    _('add ecx, 4')
    _('_px1:') ; 1px Schleife
    _('mov ebx, [esi]')
    _('mov [esi+eax], ebx')
    _('add esi, 4')
    _('dec ecx')
    _('ja _px1')
    _('ret')
    EndFunc ;==>__ASM_Move_Memory

    [/autoit]
  • Hi,
    das Prefetch muss in den loop.
    Da es immer etwas dauert bis die Daten vom RAM im Cache sind, lädt man "vorrausschauend".
    Dabei ist unbedingt zu verhindern, dass die Daten aus dem Cache "rausgedrückt" werden von Daten die bereits garnicht mehr gebraucht werden, das ist dann der Supergau!

    Leider gibt es keine Daumenregel, ein sehr interessanter Bericht findet sich (ganz unten auf der Seite) HIER! Übrigens eine meiner TOP-Favoriten bzgl.ASM-Optimierung 8o

  • Hmm...

    Ich habe es wieder überall getestet. Leider ist mein PC immer unterschiedlich schnell irgendwie.
    Manchmal braucht er für den gleichen Code 0,7ms und ein Andermal 0,6. (jeweils im Schnitt. Im Einzelfall ist eine Abweichung ja normal).
    Deshalb kann ichs nicht wirklich testen.

    Vllt geht ein Test mit größeren Grafiken. Wenn er statt 5 nur noch 4ms braucht erkennt man vllt wo der Knoten sitzt.

    Edit:
    Eben gefunden: http://blog.kaetemi.be/post/2009/10/25/SSE2-memcpy
    Gedacht: Sau cool. Das ist bestimmt verdammt schnell.

    Ergebnis: ASM: 15ms, GDI: 2,5ms^^

    Lol

    Spoiler anzeigen
    [autoit]

    Func __SSE_MoveMem()
    _('use32')
    _('org ' & FasmGetBasePtr($Fasm))
    _('mov eax, [esp+4]')
    _('mov [dst], eax')
    _('mov eax, [esp+8]')
    _('mov [src], eax')
    _('mov eax, [esp+12]')
    _('mov [nBytes], eax')

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

    _('mov ecx, [nBytes]')
    _('mov edi, [dst]')
    _('mov esi, [src]')
    _('add ecx, edi')

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

    _('prefetchnta [esi]')
    _('prefetchnta [esi+32]')
    _('prefetchnta [esi+64]')
    _('prefetchnta [esi+96]')

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

    ;~ // handle [nBytes] lower than 128
    _('cmp [nBytes], 512')
    _('jge _fast')
    _('_slow:')
    _('mov bl, [esi]')
    _('mov [edi], bl')
    _('inc edi')
    _('inc esi')
    _('cmp ecx, edi')
    _('jnz _slow')
    _('jmp _end')

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

    _('_fast:')
    ;~ // align [dst]End to 128 bytes
    _('and ecx, 0xFFFFFF80')

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

    ;~ // get [src]End aligned to [dst]End aligned to 128 bytes
    _('mov ebx, esi')
    _('sub ebx, edi')
    _('add ebx, ecx')

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

    ;~ // skip unaligned copy if [dst] is aligned
    _('mov eax, edi')
    _('and edi, 0xFFFFFF80')
    _('cmp eax, edi')
    _('jne _first')
    _('jmp _more')

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

    _('_first:')
    ;~ // copy the first 128 bytes unaligned
    _('movdqu xmm0, [esi]')
    _('movdqu xmm1, [esi+16]')
    _('movdqu xmm2, [esi+32]')
    _('movdqu xmm3, [esi+48]')

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

    _('movdqu xmm4, [esi+64]')
    _('movdqu xmm5, [esi+80]')
    _('movdqu xmm6, [esi+96]')
    _('movdqu xmm7, [esi+112]')

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

    _('movdqu [eax], xmm0')
    _('movdqu [eax+16], xmm1')
    _('movdqu [eax+32], xmm2')
    _('movdqu [eax+48], xmm3')

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

    _('movdqu [eax+64], xmm4')
    _('movdqu [eax+80], xmm5')
    _('movdqu [eax+96], xmm6')
    _('movdqu [eax+112], xmm7')

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

    ;~ // add 128 bytes to edi aligned earlier
    _('add edi, 128')

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

    ;~ // offset esi by the same value
    _('sub eax, edi')
    _('sub esi, eax')

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

    ;~ // last bytes if [dst] at [dst]End
    _('cmp ecx, edi')
    _('jnz _more')
    _('jmp last')

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

    _('_more:')
    ;~ // handle equally aligned arrays
    _('mov eax, esi')
    _('and eax, 0xFFFFFF80')
    _('cmp eax, esi')
    _('jne unaligned4k')

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

    _('aligned4k:')
    _('mov eax, esi')
    _('add eax, 4096')
    _('cmp eax, ebx')
    _('jle aligned4kin')
    _('cmp ecx, edi')
    _('jne alignedlast')
    _('jmp last')

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

    _('aligned4kin:')
    _('prefetchnta [esi]')
    _('prefetchnta [esi+32]')
    _('prefetchnta [esi+64]')
    _('prefetchnta [esi+96]')

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

    _('add esi, 128')

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

    _('cmp eax, esi')
    _('jne aligned4kin')

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

    _('sub esi, 4096')

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

    _('alinged4kout:')
    _('movdqa xmm0, [esi]')
    _('movdqa xmm1, [esi+16]')
    _('movdqa xmm2, [esi+32]')
    _('movdqa xmm3, [esi+48]')

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

    _('movdqa xmm4, [esi+64]')
    _('movdqa xmm5, [esi+80]')
    _('movdqa xmm6, [esi+96]')
    _('movdqa xmm7, [esi+112]')

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

    _('movntdq [edi], xmm0')
    _('movntdq [edi+16], xmm1')
    _('movntdq [edi+32], xmm2')
    _('movntdq [edi+48], xmm3')

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

    _('movntdq [edi+64], xmm4')
    _('movntdq [edi+80], xmm5')
    _('movntdq [edi+96], xmm6')
    _('movntdq [edi+112], xmm7')

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

    _('add esi, 128')
    _('add edi, 128')

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

    _('cmp eax, esi')
    _('jne alinged4kout')
    _('jmp aligned4k')

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

    _('alignedlast:')
    _('mov eax, esi')

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

    _('alignedlastin:')
    _('prefetchnta [esi]')
    _('prefetchnta [esi+32]')
    _('prefetchnta [esi+64]')
    _('prefetchnta [esi+96]')

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

    _('add esi, 128')

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

    _('cmp ebx, esi')
    _('jne alignedlastin')

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

    _('mov esi, eax')

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

    _('alignedlastout:')
    _('movdqa xmm0, [esi]')
    _('movdqa xmm1, [esi+16]')
    _('movdqa xmm2, [esi+32]')
    _('movdqa xmm3, [esi+48]')

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

    _('movdqa xmm4, [esi+64]')
    _('movdqa xmm5, [esi+80]')
    _('movdqa xmm6, [esi+96]')
    _('movdqa xmm7, [esi+112]')

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

    _('movntdq [edi], xmm0')
    _('movntdq [edi+16], xmm1')
    _('movntdq [edi+32], xmm2')
    _('movntdq [edi+48], xmm3')

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

    _('movntdq [edi+64], xmm4')
    _('movntdq [edi+80], xmm5')
    _('movntdq [edi+96], xmm6')
    _('movntdq [edi+112], xmm7')

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

    _('add esi, 128')
    _('add edi, 128')

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

    _('cmp ecx, edi')
    _('jne alignedlastout')
    _('jmp last')

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

    _('unaligned4k:')
    _('mov eax, esi')
    _('add eax, 4096')
    _('cmp eax, ebx')
    _('jle unaligned4kin')
    _('cmp ecx, edi')
    _('jne unalignedlast')
    _('jmp last')

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

    _('unaligned4kin:')
    _('prefetchnta [esi]')
    _('prefetchnta [esi+32]')
    _('prefetchnta [esi+64]')
    _('prefetchnta [esi+96]')

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

    _('add esi, 128')

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

    _('cmp eax, esi')
    _('jne unaligned4kin')

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

    _('sub esi, 4096')

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

    _('unalinged4kout:')
    _('movdqu xmm0, [esi]')
    _('movdqu xmm1, [esi+16]')
    _('movdqu xmm2, [esi+32]')
    _('movdqu xmm3, [esi+48]')

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

    _('movdqu xmm4, [esi+64]')
    _('movdqu xmm5, [esi+80]')
    _('movdqu xmm6, [esi+96]')
    _('movdqu xmm7, [esi+112]')

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

    _('movntdq [edi], xmm0')
    _('movntdq [edi+16], xmm1')
    _('movntdq [edi+32], xmm2')
    _('movntdq [edi+48], xmm3')

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

    _('movntdq [edi+64], xmm4')
    _('movntdq [edi+80], xmm5')
    _('movntdq [edi+96], xmm6')
    _('movntdq [edi+112], xmm7')

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

    _('add esi, 128')
    _('add edi, 128')

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

    _('cmp eax, esi')
    _('jne unalinged4kout')
    _('jmp unaligned4k')

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

    _('unalignedlast:')
    _('mov eax, esi')

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

    _('unalignedlastin:')
    _('prefetchnta [esi]')
    _('prefetchnta [esi+32]')
    _('prefetchnta [esi+64]')
    _('prefetchnta [esi+96]')

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

    _('add esi, 128')

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

    _('cmp ebx, esi')
    _('jne unalignedlastin')

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

    _('mov esi, eax')

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

    _('unalignedlastout:')
    _('movdqu xmm0, [esi]')
    _('movdqu xmm1, [esi+16]')
    _('movdqu xmm2, [esi+32]')
    _('movdqu xmm3, [esi+48]')

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

    _('movdqu xmm4, [esi+64]')
    _('movdqu xmm5, [esi+80]')
    _('movdqu xmm6, [esi+96]')
    _('movdqu xmm7, [esi+112]')

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

    _('movntdq [edi], xmm0')
    _('movntdq [edi+16], xmm1')
    _('movntdq [edi+32], xmm2')
    _('movntdq [edi+48], xmm3')

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

    _('movntdq [edi+64], xmm4')
    _('movntdq [edi+80], xmm5')
    _('movntdq [edi+96], xmm6')
    _('movntdq [edi+112], xmm7')

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

    _('add esi, 128')
    _('add edi, 128')

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

    _('cmp ecx, edi')
    _('jne unalignedlastout')
    _('jmp last')

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

    _('last:')
    ;~ // get the last 128 bytes
    _('mov ecx, [nBytes]')
    _('mov edi, [dst]')
    _('mov esi, [src]')
    _('add edi, ecx')
    _('add esi, ecx')
    _('sub edi, 128')
    _('sub esi, 128')

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

    ;~ // copy the last 128 bytes unaligned
    _('movdqu xmm0, [esi]')
    _('movdqu xmm1, [esi+16]')
    _('movdqu xmm2, [esi+32]')
    _('movdqu xmm3, [esi+48]')

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

    _('movdqu xmm4, [esi+64]')
    _('movdqu xmm5, [esi+80]')
    _('movdqu xmm6, [esi+96]')
    _('movdqu xmm7, [esi+112]')

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

    _('movdqu [edi], xmm0')
    _('movdqu [edi+16], xmm1')
    _('movdqu [edi+32], xmm2')
    _('movdqu [edi+48], xmm3')

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

    _('movdqu [edi+64], xmm4')
    _('movdqu [edi+80], xmm5')
    _('movdqu [edi+96], xmm6')
    _('movdqu [edi+112], xmm7')

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

    _('_end:')
    _('ret')
    _('nBytes dd ?')
    _('dst dd ?')
    _('src dd ?')

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

    EndFunc ;==>__SSE_MoveMem

    [/autoit]

    Ich will garnicht wissen was diese Funktion alles kann. Aber im Temop ist sie nicht wirklich Atemberaubend...^^

  • Multithreading ? Ja Bitte !

    Erste Versuche ergaben: 1,5Mal langsamer trotz 4 Threads.

    Das liegt aber im Prinzipp nur daran, dass AutoIt erst auf alle Threads warten muss (in der jetzigen Ausführung).
    Dieses "Warten" erfordert (noch) ungemein viele DllCalls, sodass das Starten und Warten und Beenden der Threads länger dauert als die Zeiterspaarnis es wieder einspielt.
    (Eine Zeitersparnis gibt es natürlich nur bei Multicore Prozessoren. Da ich einen 4Kerner habe, und Windows die Threads idr klug verteilt nutze ich hier 4 Threads. Für leute mit Dualcore: Man kann die 2 letzten Threads einfach aufkommentieren und die Ptr, sowie Bytes anpassen, sodass 2 Halbbilder statt 4 Viertelbilder genutzt werden)

    Das lässt sich aber bestimmt iwie regeln.

    Hier mal ein Beispiel:

    Spoiler anzeigen
    [autoit]

    Func _ASM_MoveMemory($Ptr_Ziel, $Ptr_Quelle, $iQBytes)

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

    Local $hDLL = DllOpen('kernel32.dll')

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

    Local $vStr = DllStructCreate('int[3]')
    DllStructSetData($vStr, 1, $Ptr_Ziel, 1)
    DllStructSetData($vStr, 1, $Ptr_Quelle, 2)
    DllStructSetData($vStr, 1, $iQBytes/4, 3)

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

    Local $Thread1 = DllCall($hDLL, "hwnd", "CreateThread", "ptr", 0, "dword", 0, "long", DllStructGetPtr($___avOP[$___ASM_OP_Move_Memory]), _
    "ptr", DllStructGetPtr($vStr), "long", 0, "int*", 0)

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

    Local $vStr2 = DllStructCreate('int[3]')
    DllStructSetData($vStr2, 1, $Ptr_Ziel+$iQBytes, 1)
    DllStructSetData($vStr2, 1, $Ptr_Quelle+$iQBytes, 2)
    DllStructSetData($vStr2, 1, $iQBytes/4, 3)

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

    Local $Thread2 = DllCall($hDLL, "hwnd", "CreateThread", "ptr", 0, "dword", 0, "long", DllStructGetPtr($___avOP[$___ASM_OP_Move_Memory]), _
    "ptr", DllStructGetPtr($vStr2), "long", 0, "int*", 0)

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

    Local $vStr3 = DllStructCreate('int[3]')
    DllStructSetData($vStr3, 1, $Ptr_Ziel+$iQBytes*2, 1)
    DllStructSetData($vStr3, 1, $Ptr_Quelle+$iQBytes*2, 2)
    DllStructSetData($vStr3, 1, $iQBytes/4, 3)

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

    Local $Thread3 = DllCall($hDLL, "hwnd", "CreateThread", "ptr", 0, "dword", 0, "long", DllStructGetPtr($___avOP[$___ASM_OP_Move_Memory]), _
    "ptr", DllStructGetPtr($vStr3), "long", 0, "int*", 0)

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

    Local $vStr4 = DllStructCreate('int[3]')
    DllStructSetData($vStr4, 1, $Ptr_Ziel+$iQBytes*3, 1)
    DllStructSetData($vStr4, 1, $Ptr_Quelle+$iQBytes*3, 2)
    DllStructSetData($vStr4, 1, $iQBytes/4, 3)

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

    Local $Thread4 = DllCall($hDLL, "hwnd", "CreateThread", "ptr", 0, "dword", 0, "long", DllStructGetPtr($___avOP[$___ASM_OP_Move_Memory]), _
    "ptr", DllStructGetPtr($vStr4), "long", 0, "int*", 0)

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

    ;~ Sleep(10)

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

    Local $Eax1[3], $Eax2[3], $Eax3[3], $Eax4[3]
    Do
    ;~ Sleep(10)

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

    $Eax1 = DllCall($hDLL, "int", "GetExitCodeThread", "ptr", $Thread1[0], "dword*", 0) ; Bis der Thread Fertig ist.
    $Eax2 = DllCall($hDLL, "int", "GetExitCodeThread", "ptr", $Thread2[0], "dword*", 0) ; Bis der Thread Fertig ist.
    $Eax3 = DllCall($hDLL, "int", "GetExitCodeThread", "ptr", $Thread3[0], "dword*", 0) ; Bis der Thread Fertig ist.
    $Eax4 = DllCall($hDLL, "int", "GetExitCodeThread", "ptr", $Thread4[0], "dword*", 0) ; Bis der Thread Fertig ist.

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

    ;~ ConsoleWrite($Eax1[2] & ' ' & $Eax2[2] & @CRLF)
    Until $Eax1[2] = 4210752250 And $Eax2[2] = 4210752250 And $Eax3[2] = 4210752250 And $Eax4[2] = 4210752250
    ;~ ConsoleWrite('Fertig...' & @CRLF)

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

    DllCall($hDLL, "int", "TerminateProcess", "ptr", $Thread1[0], "uint", 0)
    DllCall($hDLL, "int", "TerminateProcess", "ptr", $Thread2[0], "uint", 0)
    DllCall($hDLL, "int", "TerminateProcess", "ptr", $Thread3[0], "uint", 0)
    DllCall($hDLL, "int", "TerminateProcess", "ptr", $Thread4[0], "uint", 0)

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

    DllClose($hDLL)

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

    ;~ DllCall($___ASM_DLL_USER32, 'ptr', 'CallWindowProcW', 'ptr', DllStructGetPtr($___avOP[$___ASM_OP_Move_Memory]), 'ptr', DllStructGetPtr($vStr), 'ptr', 0, 'int', 0, 'int', 0)
    EndFunc

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

    Func __ASM_Move_Memory()
    _('use32')

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

    _('mov edx, [esp+4]')

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

    _('mov edi, [edx]') ; Ptr Ziel
    _('mov esi, [edx+4]') ; Ptr Quelle
    _('mov ecx, [edx+8]') ; Anzahl Pixel
    _('mov eax, edi') ;
    _('sub eax, esi') ; eax = Abstand Ziel und Quellbitmap im Ram
    _('sub ecx, 32') ; 32 Px schritte
    ;~ _('align 16')
    ;~ _('prefetch [esi+512]') ; ##################### Prefetch ?
    _('_px32:') ; 32Px - Schleife
    ;~ _('prefetchnta [esi+1024]')
    _('movdqa xmm0, [esi]')
    _('movdqa xmm1, [esi+16]')
    _('movdqa xmm2, [esi+32]')
    _('movdqa xmm3, [esi+48]')
    _('movdqa xmm4, [esi+64]')
    _('movdqa xmm5, [esi+80]')
    _('movdqa xmm6, [esi+96]')
    _('movdqa xmm7, [esi+112]')

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

    _('movdqa [esi+eax], xmm0')
    _('movdqa [esi+eax+16], xmm1')
    _('movdqa [esi+eax+32], xmm2')
    _('movdqa [esi+eax+48], xmm3')
    _('movdqa [esi+eax+64], xmm4')
    _('movdqa [esi+eax+80], xmm5')
    _('movdqa [esi+eax+96], xmm6')
    _('movdqa [esi+eax+112], xmm7')
    _('add esi, 128')
    _('sub ecx, 32')
    ;~ _('prefetchnta [esi+128]')
    _('ja _px32')
    _('add ecx, 28') ; add 32 und sub 4
    _('_px4:') ; 4px Schleife
    _('movdqa xmm0, [esi]')
    _('movdqa [esi+eax], xmm0')
    _('add esi, 16')
    _('sub ecx, 4')
    _('ja _px4')
    _('add ecx, 4')
    _('_px1:') ; 1px Schleife
    _('mov ebx, [esi]')
    _('mov [esi+eax], ebx')
    _('add esi, 4')
    _('dec ecx')
    _('ja _px1')
    _('mov eax, 0xFAFAFAFA'); Rückgabe bei Erfolg
    _('ret')
    EndFunc ;==>__ASM_Move_Memory

    [/autoit] [autoit][/autoit] [autoit][/autoit]
  • Idee:
    Threads die von AutoIt vergeben werden können, die parallel zu AutoIt laufen.
    Wenn es eine feste Anzahl Threads gibt kann man diese per AutoIt verwalten und muss nicht warten, bis sie fertig sind.
    Geprüft, ob der Thread fertig ist wird erst, wenn der Thread erneut gebraucht wird.

    Umsetzung: (provisorisch und holprig. Bitte um Nachsicht^^)
    Globale Variable für die ThreadID
    Globale Variable für die Bereitschaft des Threads.

    Wird eine Funktion (bisher nur mit MemMove gemacht) aufgerufen geschieht folgendes:
    - Thread Frei:
    1. Überprüfen ob und wenn ja, welcher Thread frei ist. (zurzeit gibts nur einen)
    2. Ist ein Thread Frei ? Dann wird er mit OPs geladen und gestartet
    3. AutoIt läuft weiter ohne zu warten.

    - Thread Besetzt:
    1. so.
    2. Wenn der Thread noch läuft wird die Funktion nicht ausgeführt. Ist der Thread fertig wird er beendet und mit OPs neu gestartet.
    3. AutoIt läuft weiter, hat die Funktion aber nicht gestartet.

    Bei mehreren Threads (z.B. 2, 3, 4 usw) kann relativ schnell geprüft werden welcher frei ist, bevor eine Funktion aufgerufen wird. Dann muss natürlich nur einer Frei sein, damit es klappt.

    Neues Beispiel
    Durch das Auslagern des ASM Codes ist der Aufruf von MemMove 3x so schnell.
    Das funktioniert aber nur, wenn unmittelbar danach nicht an Stellen in der Bitmap geschnipselt wird an denen der ASM noch am Arbeiten ist.

    Im Beispiel wird das am unteren Spieler sichtbar. Er wird gezeichnet, während noch die Monalisa gemalt wird. In der Folge wird er übermalt.
    Man kann Threads also nur einsetzen, wenn kurz nachher keine Zugriffe auf die noch zu schreibenden Stellen erfolgen.

  • Hi,
    @Marsi
    bei Win7-64 stürzt das Script ab und zu ab, manchmal läuft es 10 Sekunden, manchmal nur eine....
    Fehler ist, dass das ESI-Register mit Null bzw. einer Adresse in der Nähe von Null gefüllt ist und der Memcopy daraufhin natürlich nicht funktioniert.

    Ich würde die ganze Sache auch nicht so kompliziert machen!
    Das Script liest die Anzahl der zur Verfügung stehenden Prozessor-Kerne aus, erstellt diese Anzahl Threads (oder einen weniger) und lässt sie loslaufen.
    Gleichzeitiges Schreiben in denselben Speicherbereich würde ich persönlich nicht machen. Das führt zu flackern bei bewegten Objekten.
    Bei einem Bildbearbeitungsfilter auf Pixelebene macht Multithreading Sinn, da teilt man die Grafik in "Stücke pro Thread" und lässt die Einzelteile gleichzeitig bearbeiten.
    Das lohnt sich performancetechnisch imho aber auch nur bei komplizierten Filtern....

  • Ich verstehe nicht, was es mit esi ~ 0 auf sich hat.

    Ich hätte jetzt folgende Fehler vermutet:
    - Der Aufbau lässt nur Adressen zu die einen Abstand von Maximal 2^32/2 Bit haben, da eax immer auf die eine Adresse draufgerechnet wird (oder wenn sie dahinter liegt abgezogen) anstatt mit esi und edi zu arbeiten.
    - Evtl passen Pointer bei 64Bit Systemen nicht mehr ins 32Bt Register.

    Multithreading auf Pixelebene bekomme ich nicht gebacken. Deshalb die Idee die zu Zeichnende Grafik parallel bearbeiten zu lassen. Also ein Thread arbeitet ab dem Pointer und ein weiterer ab Pointer + Px/2. Dann hat jeder Thread nur die halbe normale Laufzeit.

    Edit: Zuvor musste ein For $i = 0 to 1000 nach dem Aufruf der ASM Func laufen um Zeit zu schinen, damit der Assembler die Struct einlesen kann.
    Das hat die Auslastung im Skript natürlich horrend in die Höhe getrieben. Ein Test mit globalen Structs zeigt: Der Funktionsaufruf dauert jetzt nur noch 0,25ms, während GDI 2,8ms am werkeln ist. Das Flackern kann man auch abschalten indem man erst an der Stelle zeichnet, nachdem der thread damit fertig ist.

    Ich finde das nicht zu umständlich. Man muss nur schauen, dass es überall läuft. Zum Glück habe ich ausreichend Computer zum Testen. (wobei alle bis auf 2 WinXP haben.).

  • - Evtl passen Pointer bei 64Bit Systemen nicht mehr ins 32Bt Register.


    Natürlich nicht. Du nimmst dann auch die 64bit-Register wie z.B. RAX, RDX, R8, RSI, ...
    Übrigens musst du auch den Stack für Parameter anders behandekn (MS x64 Fastcall statt 32bit stdcall)