GDI+ und QuickDraw zu langsam für 65000 pixel

  • ich wollte eine farbpallette darstellen allerdings braucht gdi+ und quickdraw zu lange um ca 65000 pixel darzustellen. was mache ich falsch?. gibt es eine bessere möglichkeit?.

    zeit bei mir für eine darstellung einer farbpalette

    GDI+ : 6169ms
    QuickDraw : 2284ms

    GDI+
    [autoit]

    #include <SliderConstants.au3>
    #include <GDIP.au3>

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

    $gui = GUICreate("example", 296, 256)

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

    $slider = GUICtrlCreateSlider(261, 5, 30, 251, BitOR($TBS_VERT, $TBS_TOP, $TBS_LEFT, $TBS_BOTH, $TBS_NOTICKS, $TBS_ENABLESELRANGE))
    GUICtrlSetLimit(-1, 255, 0)

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

    _GDIPlus_Startup()

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

    $graphics = _GDIPlus_GraphicsCreateFromHWND($gui)
    $bitmap = _GDIPlus_BitmapCreateFromGraphics(256, 256, $graphics)
    $buffer = _GDIPlus_ImageGetGraphicsContext($bitmap)
    $brush = _GDIPlus_BrushCreateSolid()

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

    GUISetState()

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

    While GUIGetMsg() <> -3

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

    $a = GUICtrlRead($slider)

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

    For $b = 0 To 255
    For $c = 0 To 255
    $color = String(Hex($a, 2) & Hex($b, 2) & Hex($c, 2))
    _GDIPlus_BrushSetFillColor($brush, "0xFF" & $color)
    _GDIPlus_GraphicsFillRect($buffer, $b, $c, 1, 1, $brush)
    Next
    Next

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

    _GDIPlus_GraphicsDrawImage($graphics, $bitmap, 0, 0)

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

    WEnd

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

    _GDIPlus_Shutdown()

    [/autoit]
    QuickDraw
    [autoit]

    #include <QuickDraw.au3>

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

    _QuickDraw_Enable("example", 256, 256, 0, 0, False)

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

    $a = 0

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

    HotKeySet("{RIGHT}", "Slider1")
    HotKeySet("{LEFT}", "Slider0")

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

    While _QuickDraw_Running() And GUIGetMsg() <> -16

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

    _QuickDraw_ClearBuffer(0xFF000000)

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

    For $b = 0 To 255
    For $c = 0 To 255
    $color = String(Hex($a, 2) & Hex($b, 2) & Hex($c, 2))
    _QuickDraw_Point($b, $c, "0xFF" & $color)
    Next
    Next

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

    _QuickDraw_SwapBuffers()

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

    WEnd

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

    _QuickDraw_Disable()
    Exit

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

    Func Slider0()
    If $a <> 0 Then $a -= 1
    EndFunc ;==>Slider0

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

    Func Slider1()
    If $a <> 256 Then $a += 1
    EndFunc ;==>Slider1

    [/autoit]

    Einmal editiert, zuletzt von gem (18. August 2012 um 18:58)

  • Es ist weder GDI+ noch QuickDraw das Problem, sondern AutoIt!

    256*256=256^2= 65536 Schleifendurchgänge sind für AutoIt als Intepretersprache leider zu langsam. ASM würde dir hier sehr wahrscheinlich weiterhelfen!

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Mach mal aus FillRect ein DrawLine das dürfte das 50%schneller machen.
    Oder noch besser mach ein LockBits und bearbeite es mit FASM

  • Hi,

    Zitat von UEZ

    ASM würde dir hier sehr wahrscheinlich weiterhelfen!

    was heisst hier "sehr wahrscheinlich"?*rofl*

    Ich hab da mal was vorbereitet ;)
    die Palette benötigt trotz AssembleIt nur 2ms auf meinem Gurkenrechner....

    Spoiler anzeigen
    [autoit]

    #include <SliderConstants.au3>
    #include <GDIP.au3>
    #include <assembleit.au3>

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

    Func _farbverlauf()
    _("use32")
    ; _("org " & FasmGetBasePtr($Fasm));nur für _asmdbg()
    _("mov edi,[esp+4]") ;pointer pixel
    _("mov edx,[esp+8]") ;sliderwert

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

    _("mov ecx,0") ;x=0
    _("_xschleife:") ;for x=0 to 255 grün

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

    _("mov ebx,0") ;y=0
    _("_yschleife:") ;for y=0 to 255 ;blau

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

    _("mov eax,0xFF") ;000000AA alpha
    _("shl eax,8") ;0000AA00
    _("or eax,edx") ;0000AARR rot
    _("shl eax,8") ;00AARR00
    _("or eax,ebx") ;00AARRGG grün
    _("shl eax,8") ;AARRGG00
    _("or eax,ecx") ;AARRGGBB blau
    ; _asmdbg_() ;hier kann man sich die registerinhalte anschauen wenn man möchte ;)
    _("mov [edi],eax") ;pixel an adresse schreiben
    _("add edi,4") ;nächstes pixel

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

    _("inc ebx") ;blau=blau+1
    _("cmp ebx,256") ;ist blau=256?
    _("jne _yschleife") ;nein, dann nächstes blau

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

    _("inc ecx") ;grün=grün+1
    _("cmp ecx,256") ;ist grün=256
    _("jne _xschleife") ;nein, dann nächstes grün

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

    _("ret") ;Ende

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

    EndFunc ;==>_farbverlauf

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

    $gui = GUICreate("example", 296, 256)

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

    $slider = GUICtrlCreateSlider(261, 5, 30, 251, BitOR($TBS_VERT, $TBS_TOP, $TBS_LEFT, $TBS_BOTH, $TBS_NOTICKS, $TBS_ENABLESELRANGE))
    GUICtrlSetLimit(-1, 255, 0)

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

    _GDIPlus_Startup()

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

    $graphics = _GDIPlus_GraphicsCreateFromHWND($gui)
    $bitmap = _GDIPlus_BitmapCreateFromGraphics(256, 256, $graphics)
    $buffer = _GDIPlus_ImageGetGraphicsContext($bitmap)
    $brush = _GDIPlus_BrushCreateSolid()

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

    GUISetState()

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

    $DC_gui = _WinAPI_GetDC($gui)
    Global $ptr, $hbmp ;pointer auf die pixel, handle bitmap
    $DC_bitmap = _CreateNewBmp32(256, 256, $ptr, $hbmp);bitmap erstellen

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

    While GUIGetMsg() <> -3

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

    $a = GUICtrlRead($slider)

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

    ;~ For $b = 0 To 255
    ;~ For $c = 0 To 255
    ;~ $color = "0xFF"&Hex($a, 2) & Hex($b, 2) & Hex($c, 2)
    ;~ _GDIPlus_BitmapSetPixel($bitmap,$b,$c,$color)
    ;~ ;_GDIPlus_BrushSetFillColor($brush, "0xFF" & $color)
    ;~ ;_GDIPlus_GraphicsFillRect($buffer, $b, $c, 1, 1, $brush)
    ;~ Next
    ;~ Next

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

    ; $_assembleit_flag = 1
    Local $ret = _AssembleIt("int", "_farbverlauf", "ptr", $ptr, "int", $a);stride,width,height,scan0,wert

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

    _WinAPI_BitBlt($DC_gui, 0, 0, 256, 256, $DC_bitmap, 0, 0, $srccopy)
    ;_GDIPlus_GraphicsDrawImage($graphics, $bitmap, 0, 0)

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

    WEnd

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

    _GDIPlus_Shutdown()
    _DeleteBitmap32($DC_bitmap, $ptr, $hbmp)

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

    Func _CreateNewBmp32($iwidth, $iheight, ByRef $ptr, ByRef $hbmp) ;erstellt leere 32-bit-Bitmap; Rückgabe $HDC und $ptr und handle auf die Bitmapdaten
    $hcdc = _WinAPI_CreateCompatibleDC(0) ;Desktop-Kompatiblen DeviceContext erstellen lassen
    $tBMI = DllStructCreate($tagBITMAPINFO) ;Struktur der Bitmapinfo erstellen und Daten eintragen
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4);Structgröße abzüglich der Daten für die Palette
    DllStructSetData($tBMI, "Width", $iwidth)
    DllStructSetData($tBMI, "Height", -$iheight) ;minus =standard = bottomup
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", 32) ;32 Bit = 4 Bytes => AABBGGRR
    $adib = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hbmp = $adib[0] ;hbitmap handle auf die Bitmap, auch per GDI+ zu verwenden
    $ptr = $adib[4] ;pointer auf den Anfang der Bitmapdaten, vom Assembler verwendet
    _WinAPI_SelectObject($hcdc, $hbmp) ;objekt hbitmap in DC
    Return $hcdc ;DC der Bitmap zurückgeben
    EndFunc ;==>_CreateNewBmp32

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

    Func _DeleteBitmap32($DC, $ptr, $hbmp)
    _WinAPI_DeleteDC($DC)
    _WinAPI_DeleteObject($hbmp)
    $ptr = 0
    EndFunc ;==>_DeleteBitmap32

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

    wer AssembleIt und den ASM-Code nicht mitschleppen möchte, setzt _AssembleIt_Flag=0 und verfährt nach den weiteren Anweisungen, also einfach nur mit Ctrl+v den AutoIt-Code einfügen und die Parameter in den Call kopieren.

    Dann erhält man

    Spoiler anzeigen
    [autoit]

    #include <SliderConstants.au3>
    #include <GDIP.au3>

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

    $gui = GUICreate("example", 296, 256)

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

    $slider = GUICtrlCreateSlider(261, 5, 30, 251, BitOR($TBS_VERT, $TBS_TOP, $TBS_LEFT, $TBS_BOTH, $TBS_NOTICKS, $TBS_ENABLESELRANGE))
    GUICtrlSetLimit(-1, 255, 0)

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

    ;assemblercode
    Global $tCodeBuffer = DllStructCreate("byte[62]") ;reserve Memory for opcodes
    DllStructSetData($tCodeBuffer, 1, "0x8B7C24048B542408B900000000BB00000000B8FF000000C1E00809D0C1E00809D8C1E00809C8890783C7044381FB0001000075DE4181F90001000075D0C3") ;write opcodes into memory

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

    GUISetState()

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

    $DC_gui = _WinAPI_GetDC($gui) ;DeviceContext holen
    Global $ptr, $hbmp ;pointer auf die pixel, handle bitmap
    $DC_bitmap = _CreateNewBmp32(256, 256, $ptr, $hbmp);bitmap erstellen

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

    While GUIGetMsg() <> -3
    $a = GUICtrlRead($slider)
    $ret = DllCall("user32.dll", "int", "CallWindowProcW", "ptr", DllStructGetPtr($tCodeBuffer), "ptr", $ptr, "int", $a, "int", 0, "int", 0)
    _WinAPI_BitBlt($DC_gui, 0, 0, 256, 256, $DC_bitmap, 0, 0, 0xCC0020);bitmap in DC blitten
    WEnd

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

    _DeleteBitmap32($DC_bitmap, $ptr, $hbmp)

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

    Func _CreateNewBmp32($iwidth, $iheight, ByRef $ptr, ByRef $hbmp) ;erstellt leere 32-bit-Bitmap; Rückgabe $HDC und $ptr und handle auf die Bitmapdaten
    $hcdc = _WinAPI_CreateCompatibleDC(0) ;Desktop-Kompatiblen DeviceContext erstellen lassen
    $tBMI = DllStructCreate($tagBITMAPINFO) ;Struktur der Bitmapinfo erstellen und Daten eintragen
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4);Structgröße abzüglich der Daten für die Palette
    DllStructSetData($tBMI, "Width", $iwidth)
    DllStructSetData($tBMI, "Height", -$iheight) ;minus =standard = bottomup
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", 32) ;32 Bit = 4 Bytes => AABBGGRR
    $adib = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hbmp = $adib[0] ;hbitmap handle auf die Bitmap, auch per GDI+ zu verwenden
    $ptr = $adib[4] ;pointer auf den Anfang der Bitmapdaten, vom Assembler verwendet
    _WinAPI_SelectObject($hcdc, $hbmp) ;objekt hbitmap in DC
    Return $hcdc ;DC der Bitmap zurückgeben
    EndFunc ;==>_CreateNewBmp32

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

    Func _DeleteBitmap32($DC, $ptr, $hbmp)
    _WinAPI_DeleteDC($DC)
    _WinAPI_DeleteObject($hbmp)
    $ptr = 0
    EndFunc ;==>_DeleteBitmap32

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


    die Bitmap wird dann in 0.2ms erstellt, Faktor 10000 schneller als per setpixel


    übrigens kann man natürlich auch mit den "GDI+"-Funktionen arbeiten, wenn man den DC und die $hbmp entsprechend umwandelt, einfach hinter dem "While/Wend" einfügen

    [autoit]

    _GDIPlus_Startup()
    $hGraphics = _GDIPlus_GraphicsCreateFromHDC($DC_Bitmap)
    _GDIPlus_GraphicsDrawline($hGraphics, 1, 1,200,200) ;linie zeichnen
    $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)
    _GDIPlus_ImageSaveToFile($hbitmap, "GDIPlus_Image.jpg");grafik speichern
    shellexecute("GDIPlus_Image.jpg")

    [/autoit]

    man kann das Ganze natürlich noch "extrem" beschleunigen und verkürzen, 8o

    Spoiler anzeigen
    [autoit]

    Func _farbverlauf()
    _("use32")
    ; _("org " & FasmGetBasePtr($Fasm));nur für _asmdbg()
    _("mov edi,[esp+4]") ;pointer pixel
    _("mov edx,[esp+8]") ;sliderwert

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

    _("mov eax,0xFF00") ;0000AA00 alpha
    _("or eax,edx") ;0000AARR rot
    _("shl eax,16") ;AARR0000

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

    _("mov ecx,0") ;x=0
    _("_xschleife:") ;for x=0 to 255 grün

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

    _("mov ebx,0") ;y=0
    _("_yschleife:") ;for y=0 to 255 ;blau

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

    _("mov ah,bl") ;AARRGGBB grün
    _("mov al,cl") ;AARRGGBB blau
    _("stosd")

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

    _("inc ebx") ;blau=blau+1
    _("cmp ebx,256") ;ist blau=256?
    _("jne _yschleife") ;nein, dann nächstes blau

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

    _("inc ecx") ;grün=grün+1
    _("cmp ecx,256") ;ist grün=256
    _("jne _xschleife") ;nein, dann nächstes grün

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

    _("ret") ;Ende

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

    EndFunc ;==>_farbverlauf

    [/autoit]

    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

    5 Mal editiert, zuletzt von Andy (3. März 2012 um 10:40)

  • Andy: Feine Sache! Genau sowas hatte ich mir vorgestellt, aber mit ASM bin ich seit der Primzahlen Geschichte nicht mehr vertraut, obwohl so viel Potential darin steckt!

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Naja, gerade für solche "Pixelspielereien" bietet es sich an, 20 Zeilen Code und assembliert nicht mal 60 Bytes, genau dafür ist ASM gut^^

    Interessant dabei, meinen Athlon X2 lässt das Programm völlig kalt, im wahrsten Sinne des Wortes, der wacht nichtmal aus dem P3 auf....läuft also permanent mit 800Mhz statt mit 3Ghz.
    Wahrscheinlich liegt das daran, dass der komplette Code des Loops in den Instruction Cache passt, nur einige Cache misses gibts bei jedem Aufrufen der Funktion, weil die Bitmap nicht komplett in den Cache passt^^