WinAPI: BitBlt sehr langsam, bei Verwendung von DIB

  • Hallo,

    Ich habe folgendes Problem: Ich möchte eine Reihe von Pixelfarben in einem beliebigen DC auslesen. Das ganze soll aber ohne die API-Funktion 'GetPixel' funktionieren:
    Mein Plan war es, den Inhalt des DC in eine HBitmap zu BitBlt'en. Das funktioniert auch super.

    Allerdings komme ich dann nur an die rohen Farbdaten, wenn ich diese entweder mit Hilfe von
    - LockBits() (was vorher eine Umwandlung der HBitmap in ein GDI+-Bitmap-Objekt erfordern würde),
    - oder CreateDIBSection auslese.

    BitmapLockBits ist für mich ein alter Hut - mich stört lediglich die unnötige Verschwendung von Performance, da die Bitmap-Bits erst in einen Buffer kopiert werden - weswegen ich mich für CreateDIBSection entschieden habe. Laut MSDN wird hier direkter zugriff auf die DIBits ermöglicht. Klingt ja sehr performant!

    Jetzt kommen wir zum eigentlichen Problem:
    Bei der Verwendung von CreateDIBSection ist BitBlt extrem(!) langsam - mehrere hundert millisekunden (600+ ms) ist für mich absolut nicht tragbar. Kann mir jemand sagen, warum die performance hier so mies ist? Oder am besten mit einem Verbesserungsvorschlag um die Ecke kommen? Mir ist ja bewusst, dass BitBlt hier eventuell einige kleine Konversionen durchführen muss, aber die DC's sind doch untereinander kompatibel und die DIB hat die gleiche Farbtiefe, wie der Screen-DC. Ich versteh's nicht.
    /Edit: Neuer, Kommentierter Code.

    Spoiler anzeigen
    [autoit]

    #include <Memory.au3>
    #include <WindowsConstants.au3>
    #include <WinAPI.au3>

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

    Global $_SGP2_hDC_Screen, $_SGP2_hDC_Memory, $_SGP2_pBitmapBits, $_SGP2_hMem_Alloc, $_SGP2_aArea[4]

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

    _ScreenGetPixel_2_Startup(100, 100) ; 100x100 großer DIB-Bereich

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

    $iSum = 0
    For $i = 1 To 10
    $iTimer = TimerInit()
    _ScreenGetPixel_2_Refresh(Random(0, 300, 1), Random(0, 300, 1)) ; einen 100x100 Bereich irgendwo ab X: 0-300, Y: 0-300 übertragen

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

    For $y = 0 To 99
    For $x = 0 To 99
    _ScreenGetPixel_2_GetPixel($x, $y)
    Next
    Next

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

    $iTimer = TimerDiff($iTimer)
    $iSum += $iTimer
    ConsoleWrite('Durchgang #' & $i & ': ' & $iTimer & @CRLF)
    Next

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

    ConsoleWrite('Gesamt: ' & $iSum & @CRLF)
    ConsoleWrite('Durchschnitt: ' & $iSum / $i & @CRLF)
    _ScreenGetPixel_2_Shutdown()

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

    ;==========================================================
    ; Übergeben werden muss die Größe des Bildschirmbereiches,
    ; der später übertragen werden soll. Je größer der Bereich, desto
    ; länger dauert das BitBlt beim _ScreenGetPixel_2_Refresh()
    ;==========================================================
    Func _ScreenGetPixel_2_Startup($iWidth, $iHeight, $iX = 0, $iY = 0)
    Local Const $tagBITMAPINFOHEADER = 'dword biSize;long biWidth;long biHeight;ushort biPlanes;ushort biBitCount;dword biCompression;dword biSizeImage;long biXPelsPerMeter;long biYPelsPerMeter;dword biClrUsed;dword biClrImportant;'

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

    Local $pBitmapHeader, $tBitmapHeader

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

    ; Wir holen uns zuerst den DC vom Desktop.
    $_SGP2_hDC_Screen = _WinAPI_GetDC(0)

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

    ; Dazu erstellen wir uns noch einen kompatiblen DC im Memory, der
    ; mit der DIB verknüpft wird. Wenn wir ein BitBlt in diesen DC machen,
    ; und die Farbinformationen vom Desktop-DC übertragen, enthält die DIB
    ; unsere Farbdaten.
    $_SGP2_hDC_Memory = _WinAPI_CreateCompatibleDC($_SGP2_hDC_Screen)
    ; Speicher für Bitmap-Header reservieren
    $_SGP2_hMem_Alloc = _MemGlobalAlloc(40, $GMEM_FIXED)

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

    If Not @error Then
    ; Pointer des reservierten Speichers holen
    $pBitmapHeader = _MemGlobalLock($_SGP2_hMem_Alloc)
    ; BitmapHeader in reserviertem Speicherbereich erstellen
    $tBitmapHeader = DllStructCreate($tagBITMAPINFOHEADER, $pBitmapHeader)

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

    ; Bitmapinfos ausfüllen
    DllStructSetData($tBitmapHeader, 'biSize', DllStructGetSize($tBitmapHeader))
    DllStructSetData($tBitmapHeader, 'biWidth', $iWidth)
    DllStructSetData($tBitmapHeader, 'biHeight', $iHeight)
    DllStructSetData($tBitmapHeader, 'biPlanes', 1)
    DllStructSetData($tBitmapHeader, 'biBitCount', @DesktopDepth)
    DllStructSetData($tBitmapHeader, 'biCompression', 0)
    DllStructSetData($tBitmapHeader, 'biSizeImage', 0)
    DllStructSetData($tBitmapHeader, 'biXPelsPerMeter', 0)
    DllStructSetData($tBitmapHeader, 'biYPelsPerMeter', 0)
    DllStructSetData($tBitmapHeader, 'biClrUsed', 0)
    DllStructSetData($tBitmapHeader, 'biClrImportant', 0)

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

    ; Globale Daten füllen
    $_SGP2_aArea[0] = $iX
    $_SGP2_aArea[1] = $iY
    $_SGP2_aArea[2] = $iWidth
    $_SGP2_aArea[3] = $iHeight

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

    ; DIB-Section erstellen. $_SGP2_pBitmapBits ist ein Pointer direkt auf die
    ; Farbinformationen der DIB.
    $hBitmap = _WinAPI_CreateDIBSection(0, $tBitmapHeader, 0, $_SGP2_pBitmapBits)

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

    ; DIB in den Device Context laden.
    _WinAPI_SelectObject($_SGP2_hDC_Memory, $hBitmap)

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

    _ScreenGetPixel_2_Refresh()

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

    EndIf
    EndFunc ;==>_ScreenGetPixel_2_Startup

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

    ;==========================================================
    ; Aktualisiert die Pixelfarben, die in zwischen-
    ; gespeicherter Form vorliegen.
    ;==========================================================
    Func _ScreenGetPixel_2_Refresh($iX = -1, $iY = -1)
    Local Const $SRCCOPY = 0x00CC0020 ; WindowsConstants.au3

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

    ; Wenn X oder Y Koordinate nicht mitgegeben wurde,
    ; verwende die bei StartUp angegebenen Koordinaten als
    ; linke obere Ecke.
    If $iX = -1 Then $iX = $_SGP2_aArea[0]
    If $iY = -1 Then $iY = $_SGP2_aArea[1]

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

    ; Hier passiert die Maagie!
    _WinAPI_BitBlt($_SGP2_hDC_Memory, 0, 0, $_SGP2_aArea[2], $_SGP2_aArea[3], $_SGP2_hDC_Screen, $iX, $iY, $SRCCOPY)
    EndFunc ;==>_ScreenGetPixel_2_Refresh

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

    ;==========================================================
    ; Holt eine Pixelfarbe aus den Bitmap Bits der DIB
    ;==========================================================
    Func _ScreenGetPixel_2_GetPixel($iX = 0, $iY = 0)
    Local $tStruct, $iReturn
    ; Struktur für Pixelfarbe erstellen
    $tStruct = DllStructCreate("dword", $_SGP2_pBitmapBits + ($iX * 4) + ($iY * $_SGP2_aArea[2] * 4))
    ; Farbe auslesen
    $iReturn = DllStructGetData($tStruct, 1)
    ; Struktur freigeben
    $tStruct = 0
    Return $iReturn
    EndFunc ;==>_ScreenGetPixel_2_GetPixel

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

    ;==========================================================
    ; Aufräumarbeiten. Sollte vor einem erneuten
    ; _ScreenGetPixel_2_Startup IMMER durchgeführt werden!
    ;==========================================================
    Func _ScreenGetPixel_2_Shutdown()
    ; DCs freigeben.
    _WinAPI_ReleaseDC(0, $_SGP2_hDC_Screen)
    _WinAPI_DeleteDC($_SGP2_hDC_Memory)

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

    ; Speicher für den Bitmapheader freigeben .
    _MemGlobalFree($_SGP2_hMem_Alloc)

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

    $_SGP2_hDC_Screen = 0
    $_SGP2_hDC_Memory = 0
    $_SGP2_pBitmapBits = 0
    $_SGP2_aArea[0] = 0
    $_SGP2_aArea[1] = 0
    $_SGP2_aArea[2] = 0
    $_SGP2_aArea[3] = 0
    EndFunc ;==>_ScreenGetPixel_2_Shutdown

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

    ; From WinAPIEx.au3
    ;
    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _WinAPI_CreateDIBSection
    ; Description....: Creates a DIB that applications can write to directly.
    ; Syntax.........: _WinAPI_CreateDIBSection ( $hDC, $tBITMAPINFO, $iUsage, ByRef $pBits [, $hSection [, $iOffset]] )
    ; Parameters.....: $hDC - Handle to a device context. If the value of $iUsage is $DIB_PAL_COLORS, the function uses this
    ; device context's logical palette to initialize the DIB colors.
    ; $tBITMAPINFO - $tagBITMAPINFO structure that specifies various attributes of the DIB, including the bitmap
    ; dimensions and colors.
    ; $iUsage - The type of data contained in the $pBits array. (either logical palette indexes or literal RGB values).
    ; The following values are defined.
    ;
    ; $DIB_PAL_COLORS
    ; $DIB_RGB_COLORS
    ;
    ; $pBits - A pointer to the location of the DIB bit values.
    ; $hSection - Handle to a file-mapping object that the function will use to create the DIB.
    ; $iOffset - The offset from the beginning of the file-mapping object referenced by $hSection where storage
    ; for the bitmap bit values is to begin. This value is ignored if $hSection is 0.
    ; Return values..: Success - Handle to the newly created DIB, and $pBits points to the bitmap bit values. You can create the
    ; structure by using $pBits pointer to further its filling. For example,
    ; DllStructCreate('dword[4]', $pBits).
    ; Failure - 0 and sets the @error flag to non-zero, $pBits also is 0.
    ; Author.........: Yashied
    ; Modified.......:
    ; Remarks........: When you are finished using the icon, destroy it using the _WinAPI_DestroyIcon() function.
    ; Related........:
    ; Link...........: @@MsdnLink@@ CreateDIBSection
    ; Example........: Yes
    ; ===============================================================================================================================
    Func _WinAPI_CreateDIBSection($hDC, $tBITMAPINFO, $iUsage, ByRef $pBits, $hSection = 0, $iOffset = 0)

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

    Local $Ret = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', $hDC, 'ptr', DllStructGetPtr($tBITMAPINFO), 'uint', $iUsage, 'ptr*', 0, 'ptr', $hSection, 'dword', $iOffset)

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

    If (@error) Or (Not $Ret[0]) Then
    $pBits = 0
    Else
    $pBits = $Ret[4]
    EndIf
    Return SetError(Number(Not $Ret[0]), 0, $Ret[0])
    EndFunc ;==>_WinAPI_CreateDIBSection

    [/autoit]


    Alter Code, den ich ursprünglich gepostet hatte:

    Spoiler anzeigen
    [autoit][/autoit]
    Spoiler anzeigen
    [autoit]

    [autoit]#include <Memory.au3>
    #include <WinAPIEx.au3>
    #include <WindowsConstants.au3>

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

    Global $_SGP2_hDC_Screen, $_SGP2_hDC_Memory, $_SGP2_pBitmapBits, $_SGP2_hMem_Alloc, $_SGP2_aArea[4]

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

    ;==========================================================
    ; Übergeben werden muss der Bildschirmbereich, in dem
    ; später gesucht werden soll. Je größer der bereich, desto
    ; länger dauert das BitBlt beim _ScreenGetPixel_2_Refresh()
    ;==========================================================
    Func _ScreenGetPixel_2_Startup($iX, $iY, $iWidth, $iHeight)
    Local $pBitmapHeader, $tBitmapHeader

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

    $_SGP2_hDC_Screen = _WinAPI_GetDC(0)
    $_SGP2_hDC_Memory = _WinAPI_CreateCompatibleDC($_SGP2_hDC_Screen)
    $_SGP2_hMem_Alloc = _MemGlobalAlloc(40, $GMEM_FIXED)

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

    If Not @error Then
    $pBitmapHeader = _MemGlobalLock($_SGP2_hMem_Alloc)
    $tBitmapHeader = DllStructCreate($tagBITMAPINFOHEADER, $pBitmapHeader)

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

    DllStructSetData($tBitmapHeader, 'biSize', DllStructGetSize($tBitmapHeader))
    DllStructSetData($tBitmapHeader, 'biWidth', Abs($iWidth))
    DllStructSetData($tBitmapHeader, 'biHeight', Abs($iHeight))
    DllStructSetData($tBitmapHeader, 'biPlanes', 1)
    DllStructSetData($tBitmapHeader, 'biBitCount', @DesktopDepth)
    DllStructSetData($tBitmapHeader, 'biCompression', 0)
    DllStructSetData($tBitmapHeader, 'biSizeImage', 0)
    DllStructSetData($tBitmapHeader, 'biXPelsPerMeter', 0)
    DllStructSetData($tBitmapHeader, 'biYPelsPerMeter', 0)
    DllStructSetData($tBitmapHeader, 'biClrUsed', 0)
    DllStructSetData($tBitmapHeader, 'biClrImportant', 0)

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

    $_SGP2_aArea[0] = $iX
    $_SGP2_aArea[1] = $iY
    $_SGP2_aArea[2] = $iWidth
    $_SGP2_aArea[3] = $iHeight

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

    $hBitmap = _WinAPI_CreateDIBSection(0, $tBitmapHeader, 0, $_SGP2_pBitmapBits)
    _WinAPI_SelectObject($_SGP2_hDC_Memory, $hBitmap)
    _MemGlobalFree($_SGP2_hMem_Alloc)

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

    _ScreenGetPixel_2_Refresh()

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

    EndIf
    EndFunc ;==>_ScreenGetPixel_2_Startup

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

    ;==========================================================
    ; Aktualisiert die Pixelfarben, die in zwischen-
    ; gespeicherter Form vorliegen.
    ;==========================================================
    Func _ScreenGetPixel_2_Refresh($iX = -1, $iY = -1)
    Local Const $SRCCOPY = 0x00CC0020 ; WindowsConstants.au3

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

    If $iX = -1 Then $iX = $_SGP2_aArea[0]
    If $iY = -1 Then $iY = $_SGP2_aArea[1]
    _WinAPI_BitBlt($_SGP2_hDC_Memory, 0, 0, $_SGP2_aArea[2], $_SGP2_aArea[3], $_SGP2_hDC_Screen, $iX, $iY, $SRCCOPY)
    EndFunc ;==>_ScreenGetPixel_2_Refresh

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

    ;==========================================================
    ; Holt eine Pixelfarbe aus dem Zwischenspeicher
    ;==========================================================
    Func _ScreenGetPixel_2_GetPixel($iX, $iY)
    Local $tStruct, $iReturn
    $tStruct = DllStructCreate("dword", $_SGP2_pBitmapBits + ($iX * 4) + ($iY * $_SGP2_aArea[2] * 4))
    $iReturn = DllStructGetData($tStruct, 1)
    $tStruct = 0
    Return $iReturn
    EndFunc ;==>_ScreenGetPixel_2_GetPixel

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

    ;==========================================================
    ; Aufräumarbeiten. Sollte vor einem erneuten
    ; _ScreenGetPixel_2_Startup IMMER durchgeführt werden!
    ;==========================================================
    Func _ScreenGetPixel_2_Shutdown()
    _WinAPI_ReleaseDC(0, $_SGP2_hDC_Screen)
    _WinAPI_DeleteDC($_SGP2_hDC_Memory)

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

    $_SGP2_hDC_Screen = 0
    $_SGP2_hDC_Memory = 0
    $_SGP2_pBitmapBits = 0
    $_SGP2_aArea[0] = 0
    $_SGP2_aArea[1] = 0
    $_SGP2_aArea[2] = 0
    $_SGP2_aArea[3] = 0
    EndFunc ;==>_ScreenGetPixel_2_Shutdown

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


    Gruß, SEuBo

  • Hi,
    mit

    [autoit]

    $t=timerinit()
    $a=_ScreenGetPixel_2_Startup(0,0,1000,1000)
    $m=timerdiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    $t=timerinit()
    $a=_ScreenGetPixel_2_GetPixel(800,800)
    $m=timerdiff($t)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console

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

    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $a = ' & $a & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console

    [/autoit]

    erhalte ich

    Code
    @@ Debug(11) : $m = 4.66400059225404
    >Error code: 0
    @@ Debug(16) : $m = 0.038273020733082
    >Error code: 0
    @@ Debug(18) : $a = 16777215
    >Error code: 0
  • Das schaut ja sehr gut aus. Liegt das tatsächlich nur an meinem Rechner? Ich bekomme nämlich

    Spoiler anzeigen
    Code
    @@ Debug(9) : $m = 250.395822193106
    >Error code: 0
    @@ Debug(13) : $m = 0.4038609998254892
    >Error code: 0
    @@ Debug(15) : $a = 4293981433
    >Error code: 0

    Das ist schonmal einen Zacken besser, aber immer noch viel zu langsam. o.o
    Was ist dein Ergebnis, wenn du den neuen Code (Startpost) durchlaufen lässt?

  • Hab dein Script mal bissl abgeändert und komme so nur auf 1/6 der Zeit

    Spoiler anzeigen
    [autoit]

    #include <Memory.au3>
    #include <WindowsConstants.au3>
    #include <WinAPI.au3>

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

    Global $_SGP2_hDC_Screen, $_SGP2_hDC_Memory, $_SGP2_pBitmapBits, $_SGP2_hMem_Alloc, $_SGP2_aArea[4];, $tstruct

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

    $B = 100
    $H = 100

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

    _ScreenGetPixel_2_Startup($B, $H) ; 100x100 großer DIB-Bereich

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

    $iSum = 0
    For $i = 1 To 10
    _ScreenGetPixel_2_Refresh(0, 0) ;Random(0, 300, 1), Random(0, 300, 1)) ; einen 100x100 Bereich irgendwo ab X: 0-300, Y: 0-300 übertragen

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


    ;*********GEÄNDERT*********
    $tstruct = DllStructCreate("dword[" & $B * $H & "]", $_SGP2_pBitmapBits)
    ;**************************
    $iTimer = TimerInit()
    For $y = 0 To 99
    For $x = 0 To 99
    $iReturn = DllStructGetData($tstruct, 1, $y * $B + $x)
    ;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $iReturn = ' & $iReturn & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    Next
    Next

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

    $iTimer = TimerDiff($iTimer)
    $iSum += $iTimer
    ConsoleWrite('Durchgang #' & $i & ': ' & $iTimer & @CRLF)
    Next

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

    ConsoleWrite('Gesamt: ' & $iSum & @CRLF)
    ConsoleWrite('Durchschnitt: ' & $iSum / $i & @CRLF)
    _ScreenGetPixel_2_Shutdown()

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

    ;==========================================================
    ; Übergeben werden muss die Größe des Bildschirmbereiches,
    ; der später übertragen werden soll. Je größer der Bereich, desto
    ; länger dauert das BitBlt beim _ScreenGetPixel_2_Refresh()
    ;==========================================================
    Func _ScreenGetPixel_2_Startup($iWidth, $iHeight, $iX = 0, $iY = 0)
    Local Const $tagBITMAPINFOHEADER = 'dword biSize ;long biWidth;long biHeight;ushort biPlanes;ushort biBitCount;dword biCompression;dword biSizeImage;long biXPelsPerMeter;long biYPelsPerMeter;dword biClrUsed;dword biClrImportant;'

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

    Local $pBitmapHeader, $tBitmapHeader

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

    ; Wir holen uns zuerst den DC vom Desktop.
    $_SGP2_hDC_Screen = _WinAPI_GetDC(0)

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

    ; Dazu erstellen wir uns noch einen kompatiblen DC im Memory, der
    ; mit der DIB verknüpft wird. Wenn wir ein BitBlt in diesen DC machen,
    ; und die Farbinformationen vom Desktop-DC übertragen, enthält die DIB
    ; unsere Farbdaten.
    $_SGP2_hDC_Memory = _WinAPI_CreateCompatibleDC($_SGP2_hDC_Screen)
    ; Speicher für Bitmap-Header reservieren
    $_SGP2_hMem_Alloc = _MemGlobalAlloc(40, $GMEM_FIXED)

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

    If Not @error Then
    ; Pointer des reservierten Speichers holen
    $pBitmapHeader = _MemGlobalLock($_SGP2_hMem_Alloc)
    ; BitmapHeader in reserviertem Speicherbereich erstellen
    $tBitmapHeader = DllStructCreate($tagBITMAPINFOHEADER, $pBitmapHeader)

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

    ; Bitmapinfos ausfüllen
    DllStructSetData($tBitmapHeader, 'biSize', DllStructGetSize($tBitmapHeader))
    DllStructSetData($tBitmapHeader, 'biWidth', $iWidth)
    DllStructSetData($tBitmapHeader, 'biHeight', $iHeight)
    DllStructSetData($tBitmapHeader, 'biPlanes', 1)
    DllStructSetData($tBitmapHeader, 'biBitCount', @DesktopDepth)
    DllStructSetData($tBitmapHeader, 'biCompression', 0)
    DllStructSetData($tBitmapHeader, 'biSizeImage', 0)
    DllStructSetData($tBitmapHeader, 'biXPelsPerMeter', 0)
    DllStructSetData($tBitmapHeader, 'biYPelsPerMeter', 0)
    DllStructSetData($tBitmapHeader, 'biClrUsed', 0)
    DllStructSetData($tBitmapHeader, 'biClrImportant', 0)

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

    ; Globale Daten füllen
    $_SGP2_aArea[0] = $iX
    $_SGP2_aArea[1] = $iY
    $_SGP2_aArea[2] = $iWidth
    $_SGP2_aArea[3] = $iHeight

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

    ; DIB-Section erstellen. $_SGP2_pBitmapBits ist ein Pointer direkt auf die
    ; Farbinformationen der DIB.
    $hBitmap = _WinAPI_CreateDIBSection(0, $tBitmapHeader, 0, $_SGP2_pBitmapBits)

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

    ; DIB in den Device Context laden.
    _WinAPI_SelectObject($_SGP2_hDC_Memory, $hBitmap)

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

    _ScreenGetPixel_2_Refresh()

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

    EndIf
    EndFunc ;==>_ScreenGetPixel_2_Startup

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

    ;==========================================================
    ; Aktualisiert die Pixelfarben, die in zwischen-
    ; gespeicherter Form vorliegen.
    ;==========================================================
    Func _ScreenGetPixel_2_Refresh($iX = -1, $iY = -1)
    Local Const $SRCCOPY = 0x00CC0020 ; WindowsConstants.au3

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

    ; Wenn X oder Y Koordinate nicht mitgegeben wurde,
    ; verwende die bei StartUp angegebenen Koordinaten als
    ; linke obere Ecke.
    If $iX = -1 Then $iX = $_SGP2_aArea[0]
    If $iY = -1 Then $iY = $_SGP2_aArea[1]
    ; Hier passiert die Maagie!
    _WinAPI_BitBlt($_SGP2_hDC_Memory, 0, 0, $_SGP2_aArea[2], $_SGP2_aArea[3], $_SGP2_hDC_Screen, $iX, $iY, $SRCCOPY)
    EndFunc ;==>_ScreenGetPixel_2_Refresh

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

    ;==========================================================
    ; Holt eine Pixelfarbe aus den Bitmap Bits der DIB
    ;==========================================================
    Func _ScreenGetPixel_2_GetPixel($iX = 0, $iY = 0)
    Local $iReturn
    ; Struktur für Pixelfarbe erstellen

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

    ; Farbe auslesen

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

    ; Struktur freigeben
    $tstruct = 0
    Return $iReturn
    EndFunc ;==>_ScreenGetPixel_2_GetPixel

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

    ;==========================================================
    ; Aufräumarbeiten. Sollte vor einem erneuten
    ; _ScreenGetPixel_2_Startup IMMER durchgeführt werden!
    ;==========================================================
    Func _ScreenGetPixel_2_Shutdown()
    ; DCs freigeben.
    _WinAPI_ReleaseDC(0, $_SGP2_hDC_Screen)
    _WinAPI_DeleteDC($_SGP2_hDC_Memory)

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

    ; Speicher für den Bitmapheader freigeben .
    _MemGlobalFree($_SGP2_hMem_Alloc)

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

    $_SGP2_hDC_Screen = 0
    $_SGP2_hDC_Memory = 0
    $_SGP2_pBitmapBits = 0
    $_SGP2_aArea[0] = 0
    $_SGP2_aArea[1] = 0
    $_SGP2_aArea[2] = 0
    $_SGP2_aArea[3] = 0
    EndFunc ;==>_ScreenGetPixel_2_Shutdown

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

    ; From WinAPIEx.au3
    ;
    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _WinAPI_CreateDIBSection
    ; Description....: Creates a DIB that applications can write to directly.
    ; Syntax.........: _WinAPI_CreateDIBSection ( $hDC, $tBITMAPINFO, $iUsage, ByRef $pBits [, $hSection [, $iOffset]] )
    ; Parameters.....: $hDC - Handle to a device context. If the value of $iUsage is $DIB_PAL_COLORS, the function uses this
    ; device context's logical palette to initialize the DIB colors.
    ; $tBITMAPINFO - $tagBITMAPINFO structure that specifies various attributes of the DIB, including the bitmap
    ; dimensions and colors.
    ; $iUsage - The type of data contained in the $pBits array. (either logical palette indexes or literal RGB values).
    ; The following values are defined.
    ;
    ; $DIB_PAL_COLORS
    ; $DIB_RGB_COLORS
    ;
    ; $pBits - A pointer to the location of the DIB bit values.
    ; $hSection - Handle to a file-mapping object that the function will use to create the DIB.
    ; $iOffset - The offset from the beginning of the file-mapping object referenced by $hSection where storage
    ; for the bitmap bit values is to begin. This value is ignored if $hSection is 0.
    ; Return values..: Success - Handle to the newly created DIB, and $pBits points to the bitmap bit values. You can create the
    ; structure by using $pBits pointer to further its filling. For example,
    ; DllStructCreate('dword[4]', $pBits).
    ; Failure - 0 and sets the @error flag to non-zero, $pBits also is 0.
    ; Author.........: Yashied
    ; Modified.......:
    ; Remarks........: When you are finished using the icon, destroy it using the _WinAPI_DestroyIcon() function.
    ; Related........:
    ; Link...........: @@MsdnLink@@ CreateDIBSection
    ; Example........: Yes
    ; ===============================================================================================================================
    Func _WinAPI_CreateDIBSection($hDC, $tBITMAPINFO, $iUsage, ByRef $pBits, $hSection = 0, $iOffset = 0)

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

    Local $Ret = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', $hDC, 'ptr', DllStructGetPtr($tBITMAPINFO), 'uint', $iUsage, 'ptr*', 0, 'ptr', $hSection, 'dword', $iOffset)

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

    If (@error) Or (Not $Ret[0]) Then
    $pBits = 0
    Else
    $pBits = $Ret[4]
    EndIf
    Return SetError(Number(Not $Ret[0]), 0, $Ret[0])
    EndFunc ;==>_WinAPI_CreateDIBSection

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


    vorher:

    nachher:

    Weiterhin holt man noch mehr Geschwindigkeit heraus, indem man SÄMTLICHE nicht für den "Inner Loop" benötigten Befehle WEGLÄSST!
    ALLES, das heisst ALLES, was nicht unbedingt in den inner Loop gehört , KOMMT RAUS!
    D.h. auch sämtliches Fehlermananagement usw., das lagert man immer in die vorhergehenden Anweisungen aus.

    /EDIT/ z.B. Stoppst du 2x die RANDOM-Funktion mit^^
    Bitblt ist ziemlich schnell, in einer while/wend-schleife mit einem ausschliesslichen BitBlt() drin erreiche ich knapp 1000FPS bei 1680x1050

    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 (13. März 2012 um 20:07)

  • Hab dein Script mal bissl abgeändert und komme so nur auf 1/6 der Zeit


    Das könnte daran liegen, dass du das BitBlt jetzt nicht mehr mit Berücksichtigst ;)

    Die Struct auszulagern, war eigentlich keine schlechte Idee - komme jetzt mit meiner Kröte von Laptop (Früher war er mal schnell :D) auf durchschnittlich 120 ms.
    Außerdem scheint auch der Funktionsaufruf von _ScreenGetPixel_2_GetPixel() (~120 ms) im Gegensatz zum direkten Aufruf von DLLStructGetData() (~60ms) einiges an Zeit zu fressen.
    Auf den kann ich aber eigentlich nicht verzichten - da das ganze eine UDF werden sollte, falls jemand sowas mal braucht, sollte es auch komfortabel gehalten sein.

    Aber vielen vielen Dank für die Mühe Andy. Du hast mir schonmal ein ganzes Stück weitergeholfen - habe das ganze jetzt so, und ich denke mal, ich werde es so lassen:

    Spoiler anzeigen
    [autoit]

    #include <Memory.au3>
    #include <WindowsConstants.au3>
    #include <WinAPI.au3>

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

    Global $_SGP2_hGDI32DLL, $_SGP2_hDC_Screen, $_SGP2_hDC_Memory, $_SGP2_pBitmapBits, $_SGP2_tStruct, $_SGP2_hMem_Alloc
    Global $_SGP2_aArea_0, $_SGP2_aArea_1, $_SGP2_aArea_2, $_SGP2_aArea_3
    _ScreenGetPixel_2_Startup(100, 100) ; 100x100 großer DIB-Bereich

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

    $iSum = 0
    For $i = 1 To 10
    $iTimer = TimerInit()
    _ScreenGetPixel_2_Refresh(0, 0)

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

    For $y = 0 To 99
    For $x = 0 To 99
    _ScreenGetPixel_2_GetPixel($x, $y)
    Next
    Next

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

    $iTimer = TimerDiff($iTimer)
    $iSum += $iTimer
    ConsoleWrite('Durchgang #' & $i & ': ' & $iTimer & @CRLF)
    Next

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

    ConsoleWrite('Gesamt: ' & $iSum & @CRLF)
    ConsoleWrite('Durchschnitt: ' & $iSum / ($i - 1) & @CRLF)
    _ScreenGetPixel_2_Shutdown()

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

    ;==========================================================
    ; Übergeben werden muss die Größe des Bildschirmbereiches,
    ; der später übertragen werden soll. Je größer der Bereich, desto
    ; länger dauert das BitBlt beim _ScreenGetPixel_2_Refresh()
    ;==========================================================
    Func _ScreenGetPixel_2_Startup($iWidth, $iHeight, $iX = 0, $iY = 0)
    Local Const $tagBITMAPINFOHEADER = 'dword biSize;long biWidth;long biHeight;ushort biPlanes;ushort biBitCount;dword biCompression;dword biSizeImage;long biXPelsPerMeter;long biYPelsPerMeter;dword biClrUsed;dword biClrImportant;'

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

    Local $pBitmapHeader, $tBitmapHeader

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

    ; Wir holen uns zuerst den DC vom Desktop.
    $_SGP2_hDC_Screen = _WinAPI_GetDC(0)

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

    ; Dazu erstellen wir uns noch einen kompatiblen DC im Memory, der
    ; mit der DIB verknüpft wird. Wenn wir ein BitBlt in diesen DC machen,
    ; und die Farbinformationen vom Desktop-DC übertragen, enthält die DIB
    ; unsere Farbdaten.
    $_SGP2_hDC_Memory = _WinAPI_CreateCompatibleDC($_SGP2_hDC_Screen)
    ; Speicher für Bitmap-Header reservieren
    $_SGP2_hMem_Alloc = _MemGlobalAlloc(40, $GMEM_FIXED)

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

    If Not @error Then
    ; Pointer des reservierten Speichers holen
    $pBitmapHeader = _MemGlobalLock($_SGP2_hMem_Alloc)
    ; BitmapHeader in reserviertem Speicherbereich erstellen
    $tBitmapHeader = DllStructCreate($tagBITMAPINFOHEADER, $pBitmapHeader)

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

    ; Bitmapinfos ausfüllen
    DllStructSetData($tBitmapHeader, 'biSize', DllStructGetSize($tBitmapHeader))
    DllStructSetData($tBitmapHeader, 'biWidth', $iWidth)
    DllStructSetData($tBitmapHeader, 'biHeight', $iHeight)
    DllStructSetData($tBitmapHeader, 'biPlanes', 1)
    DllStructSetData($tBitmapHeader, 'biBitCount', @DesktopDepth)
    DllStructSetData($tBitmapHeader, 'biCompression', 0)
    DllStructSetData($tBitmapHeader, 'biSizeImage', 0)
    DllStructSetData($tBitmapHeader, 'biXPelsPerMeter', 0)
    DllStructSetData($tBitmapHeader, 'biYPelsPerMeter', 0)
    DllStructSetData($tBitmapHeader, 'biClrUsed', 0)
    DllStructSetData($tBitmapHeader, 'biClrImportant', 0)

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

    ; Globale Daten füllen
    $_SGP2_aArea_0 = $iX
    $_SGP2_aArea_1 = $iY
    $_SGP2_aArea_2 = $iWidth
    $_SGP2_aArea_3 = $iHeight

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

    ; DIB-Section erstellen. $_SGP2_pBitmapBits ist ein Pointer direkt auf die
    ; Farbinformationen der DIB.
    $hBitmap = _WinAPI_CreateDIBSection(0, $tBitmapHeader, 0, $_SGP2_pBitmapBits)

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

    ; Struktur für Pixelfarbe erstellen
    $_SGP2_tStruct = DllStructCreate('dword[' & $iWidth * $iHeight & ']', $_SGP2_pBitmapBits)

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

    ; DIB in den Device Context laden.
    _WinAPI_SelectObject($_SGP2_hDC_Memory, $hBitmap)

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

    $_SGP2_hGDI32DLL = DllOpen('gdi32.dll')
    _ScreenGetPixel_2_Refresh()

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

    EndIf
    EndFunc ;==>_ScreenGetPixel_2_Startup

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

    ;==========================================================
    ; Aktualisiert die Pixelfarben, die in zwischen-
    ; gespeicherter Form vorliegen.
    ;==========================================================
    Func _ScreenGetPixel_2_Refresh($iX = -1, $iY = -1)
    Local Const $SRCCOPY = 0x00CC0020 ; WindowsConstants.au3

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

    ; Wenn X oder Y Koordinate nicht mitgegeben wurde,
    ; verwende die bei StartUp angegebenen Koordinaten als
    ; linke obere Ecke.
    If $iX = -1 Then $iX = $_SGP2_aArea_0
    If $iY = -1 Then $iY = $_SGP2_aArea_1

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

    ; Hier passiert die Maagie!
    __WinAPI_BitBlt($_SGP2_hDC_Memory, 0, 0, $_SGP2_aArea_2, $_SGP2_aArea_3, $_SGP2_hDC_Screen, $iX, $iY, $SRCCOPY)
    EndFunc ;==>_ScreenGetPixel_2_Refresh

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

    ;==========================================================
    ; Holt eine Pixelfarbe aus den Bitmap Bits der DIB
    ;==========================================================
    Func _ScreenGetPixel_2_GetPixel($iX, $iY)
    Return DllStructGetData($_SGP2_tStruct, 1, $iX + $iY * $_SGP2_aArea_2)
    EndFunc ;==>_ScreenGetPixel_2_GetPixel

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

    ;==========================================================
    ; Aufräumarbeiten. Sollte vor einem erneuten
    ; _ScreenGetPixel_2_Startup IMMER durchgeführt werden!
    ;==========================================================
    Func _ScreenGetPixel_2_Shutdown()
    ; DCs freigeben.
    _WinAPI_ReleaseDC(0, $_SGP2_hDC_Screen)
    _WinAPI_DeleteDC($_SGP2_hDC_Memory)

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

    ; Speicher für den Bitmapheader freigeben .
    _MemGlobalFree($_SGP2_hMem_Alloc)
    DllClose($_SGP2_hGDI32DLL)

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

    $_SGP2_hDC_Screen = 0
    $_SGP2_hDC_Memory = 0
    $_SGP2_pBitmapBits = 0
    $_SGP2_aArea_0 = 0
    $_SGP2_aArea_1 = 0
    $_SGP2_aArea_2 = 0
    $_SGP2_aArea_3 = 0
    EndFunc ;==>_ScreenGetPixel_2_Shutdown

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

    ; From WinAPIEx.au3
    ;
    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _WinAPI_CreateDIBSection
    ; Description....: Creates a DIB that applications can write to directly.
    ; Syntax.........: _WinAPI_CreateDIBSection ( $hDC, $tBITMAPINFO, $iUsage, ByRef $pBits [, $hSection [, $iOffset]] )
    ; Parameters.....: $hDC - Handle to a device context. If the value of $iUsage is $DIB_PAL_COLORS, the function uses this
    ; device context's logical palette to initialize the DIB colors.
    ; $tBITMAPINFO - $tagBITMAPINFO structure that specifies various attributes of the DIB, including the bitmap
    ; dimensions and colors.
    ; $iUsage - The type of data contained in the $pBits array. (either logical palette indexes or literal RGB values).
    ; The following values are defined.
    ;
    ; $DIB_PAL_COLORS
    ; $DIB_RGB_COLORS
    ;
    ; $pBits - A pointer to the location of the DIB bit values.
    ; $hSection - Handle to a file-mapping object that the function will use to create the DIB.
    ; $iOffset - The offset from the beginning of the file-mapping object referenced by $hSection where storage
    ; for the bitmap bit values is to begin. This value is ignored if $hSection is 0.
    ; Return values..: Success - Handle to the newly created DIB, and $pBits points to the bitmap bit values. You can create the
    ; structure by using $pBits pointer to further its filling. For example,
    ; DllStructCreate('dword[4]', $pBits).
    ; Failure - 0 and sets the @error flag to non-zero, $pBits also is 0.
    ; Author.........: Yashied
    ; Modified.......:
    ; Remarks........: When you are finished using the icon, destroy it using the _WinAPI_DestroyIcon() function.
    ; Related........:
    ; Link...........: @@MsdnLink@@ CreateDIBSection
    ; Example........: Yes
    ; ===============================================================================================================================
    Func _WinAPI_CreateDIBSection($hDC, $tBITMAPINFO, $iUsage, ByRef $pBits, $hSection = 0, $iOffset = 0)

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

    Local $Ret = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', $hDC, 'ptr', DllStructGetPtr($tBITMAPINFO), 'uint', $iUsage, 'ptr*', 0, 'ptr', $hSection, 'dword', $iOffset)

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

    If (@error) Or (Not $Ret[0]) Then
    $pBits = 0
    Else
    $pBits = $Ret[4]
    EndIf
    Return SetError(Number(Not $Ret[0]), 0, $Ret[0])
    EndFunc ;==>_WinAPI_CreateDIBSection

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

    ; #FUNCTION# ====================================================================================================================
    ; Name...........: _WinAPI_BitBlt
    ; Description ...: Performs a bit-block transfer of color data
    ; Syntax.........: _WinAPI_BitBlt($hDestDC, $iXDest, $iYDest, $iWidth, $iHeight, $hSrcDC, $iXSrc, $iYSrc, $iROP)
    ; Parameters ....: $hDestDC - Handle to the destination device context
    ; $iXDest - X value of the upper-left corner of the destination rectangle
    ; $iYDest - Y value of the upper-left corner of the destination rectangle
    ; $iWidth - Width of the source and destination rectangles
    ; $iHeight - Height of the source and destination rectangles
    ; $hSrcDC - Handle to the source device context
    ; $iXSrc - X value of the upper-left corner of the source rectangle
    ; $iYSrc - Y value of the upper-left corner of the source rectangle
    ; $iROP - Specifies a raster operation code. These codes define how the color data for the source
    ; +rectangle is to be combined with the color data for the destination rectangle to achieve the final color:
    ; |$BLACKNESS - Fills the destination rectangle using the color associated with palette index 0
    ; |$CAPTUREBLT - Includes any window that are layered on top of your window in the resulting image
    ; |$DSTINVERT - Inverts the destination rectangle
    ; |$MERGECOPY - Merges the color of the source rectangle with the brush currently selected in hDest, by
    ; +using the AND operator.
    ; |$MERGEPAINT - Merges the color of the inverted source rectangle with the colors of the destination
    ; +rectangle by using the OR operator.
    ; |$NOMIRRORBITMAP - Prevents the bitmap from being mirrored
    ; |$NOTSRCCOPY - Copies the inverted source rectangle to the destination
    ; |$NOTSRCERASE - Combines the colors of the source and destination rectangles by using the OR operator and
    ; +then inverts the resultant color.
    ; |$PATCOPY - Copies the brush selected in hdcDest, into the destination bitmap
    ; |$PATINVERT - Combines the colors of the brush currently selected in hDest, with the colors of the
    ; +destination rectangle by using the XOR operator.
    ; |$PATPAINT - Combines the colors of the brush currently selected in hDest, with the colors of the
    ; +inverted source rectangle by using the OR operator. The result of this operation is combined with the color
    ; +of the destination rectangle by using the OR operator.
    ; |$SRCAND - Combines the colors of the source and destination rectangles by using the AND operator
    ; |$SRCCOPY - Copies the source rectangle directly to the destination rectangle
    ; |$SRCERASE - Combines the inverted color of the destination rectangle with the colors of the source
    ; +rectangle by using the AND operator.
    ; |$SRCINVERT - Combines the colors of the source and destination rectangles by using the XOR operator
    ; |$SRCPAINT - Combines the colors of the source and destination rectangles by using the OR operator
    ; |$WHITENESS - Fills the destination rectangle using the color associated with index 1 in the physical
    ; +palette.
    ; Return values .: Success - True
    ; Failure - False
    ; Author ........: Paul Campbell (PaulIA)
    ; Modified.......:
    ; Remarks .......:
    ; Related .......:
    ; Link ..........: @@MsdnLink@@ BitBlt
    ; Example .......:
    ; ===============================================================================================================================
    Func __WinAPI_BitBlt($hDestDC, $iXDest, $iYDest, $iWidth, $iHeight, $hSrcDC, $iXSrc, $iYSrc, $iROP)
    Local $aResult = DllCall($_SGP2_hGDI32DLL, "bool", "BitBlt", "handle", $hDestDC, "int", $iXDest, "int", $iYDest, "int", $iWidth, "int", $iHeight, _
    "handle", $hSrcDC, "int", $iXSrc, "int", $iYSrc, "dword", $iROP)
    If @error Then Return SetError(@error, @extended, False)
    Return $aResult[0]
    EndFunc ;==>__WinAPI_BitBlt

    [/autoit]
  • /OT/ BitBlt ist nicht wirklich langsam^^

    Spoiler anzeigen
    [autoit]

    #include <GDIPlus.au3>
    #include <WinAPI.au3>

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

    opt("GUIOnEventMode",1)
    opt("GUICloseOnESC",1)

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

    _GDIPlus_Startup()

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

    $hgui=guicreate("",1024,768)
    guisetstate()
    GUISetOnEvent(-3, '_Exit', $hGUI)
    $hDC_gui = _WinAPI_GetDC($hGUI)
    $hDC = _WinAPI_GetDC(0)
    AdlibRegister("_FPS", 1000)

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

    global $fps=0

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

    while 1
    _WinAPI_BitBlt($hdc_gui, 0, 0, 1024, 768, $hdc, $fps/10, $fps/100, 0x00CC0020 );image in leere bitmap
    $fps+=1
    WEnd

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

    Func _FPS()
    WinSetTitle($hGUI, "", "FPS=" & $FPS )
    $FPS = 0
    EndFunc ;==>_FPS

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

    func _Exit()
    exit
    EndFunc

    [/autoit]


    wenn man die /10 und /100 im BitBlt entfernt, verfünffachen sich die Frameraten, auf meinem Gurkenrechner auf >6000
    d.h. ein blit vom Screen in ein Fenster dauert weniger als 0.1ms

    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 (13. März 2012 um 21:53)

  • Andy: Es ist ein kleiner Unterschied, ob man mit DIBs oder Device Dependent Bitmaps arbeitet denke ich.

  • Zitat

    Andy: Es ist ein kleiner Unterschied, ob man mit DIBs oder Device Dependent Bitmaps arbeitet denke ich.


    Fürs blitten (auf dem Bildschirm) macht das imho keinen Unterschied (jedenfalls bei herkömmlichen Frameraten). Da werden Bytes durch den Speicher geschoben. Auf anderen Devices sieht das sicher anders aus, aber da wird der Treiber dazwischenfunken bzgl Formaten usw.

    Zitat von MSDN

    ...Thus, a DDB is often called a compatible bitmap and it usually has better GDI performance than a DIB. For example, to create a bitmap for video memory, it is best to use a compatible bitmap with the same color format as the primary display. Once in video memory, rendering to the bitmap and displaying it to the screen are significantly faster than from a system memory surface or directly from a DIB....

    significantly....wzbw, du darfst aktiv werden ;)

  • Ich schätze, dass das Problem hier liegt:

    Zitat

    You need to guarantee that the GDI subsystem has completed any drawing to a bitmap created by CreateDIBSection before you draw to the bitmap yourself. Access to the bitmap must be synchronized. Do this by calling the GdiFlush function. This applies to any use of the pointer to the bitmap bit values, including passing the pointer in calls to functions such as SetDIBits.

    Warum nimmst du nicht GetDIBits?

  • ja, die gesamte Umwandelei DIB/DDB und vv kostet einfach Zeit(wenn es auch nur einige zehntel ms sind....)

    Aber das ist nichtmal das große Problem. 400.000 Bytes in nicht mal einer halben Sekunde aus dem Speicher auszulesen finde ich für eine Scriptsprache schon beachtlich.
    Was im Testscript aber überhaupt nicht beachtet wird ist die Weiterverarbeitung. Wo sollen denn die einzelnen Pixel hin? In ein Array? :rofl:
    Irgend etwas soll ja damit passieren, einfach nur "auslesen" ist imho sinnlos, dann stehen die "Pixel" nur doppelt im Speicher.
    Und bearbeiten? Ggf. lesen/schreiben? Das mag für einige Handvoll Pixel noch machbar sein, aber bei großen Datenmengen, also FullHD, reden wir mal schnell über 1920x1080x4=8,3MB
    Für das Auslesen der "Pixel" braucht AutoIt dann 15 Sekunden, der Bitblt 5ms, insgesamt 0,06FPS
    Per C oder ASM relativiert sich das, auslesen+bearbeiten 10ms, Blit 5ms, insgesamt 66FPS

    Datenbewegungen/Bearbeitungen per GDI laufen natürlich innerhalb des Videospeichers wesentlich schneller ab, als vom Hauptspeicher(über den Bus+Treiber) in den Videospeicher.
    Daher ist auch ein "Blit" (nichts anderes als ein memcopy) zwischen zwei DC´s im Videomemory viel schneller als ein Blit von einem DC im Hauptspeicher in den DC im Videospeicher.