SetBits / GetBits gut genug?
Re: SetBits / GetBits gut genug?
Die FPU macht mich noch wahnsinning
Ich hänge noch bei der Konvertierung der Dither Funktion
Ware für jede Hilfe Dankbar.
Hier der Assembly Code:
Der PureBasic Code:
Das Ergebnis der Rechnung is nicht korrekt!?
-> Pixel\RGB[0] * Factor

Ich hänge noch bei der Konvertierung der Dither Funktion
Ware für jede Hilfe Dankbar.
Hier der Assembly Code:
Code: Alles auswählen
format MS64 COFF
public nifDitherRGB
section '.text' code readable executable
nifDitherRGB:;*Pixel(Pointer zur RGB Struktur),*Exit(Pointer zum Lezten Pixel),*Error(Pointer zur Error Variable),Factor(Float)
;------------------------------------------ SETUP STACK FRAME
push rbp
mov rbp,rsp
;------------------------------------------ ALLOCATE SPACE FOR LOCAL VARIABLES
sub rsp,48h
;------------------------------------------ SET DEFAULT RETURN
xor rax,rax
;------------------------------------------ POINTER VERIFICATION
cmp rcx,rdx
jnb @f
;------------------------------------------ LOAD FACTOR
mov[rbp-8h],r9
;------------------------------------------ LOAD PIXEL (RGB)
movzx rdx,byte[rcx]
mov[rbp-28h],rdx
movzx rdx,byte[rcx+1h]
mov[rbp-30h],rdx
movzx rdx,byte[rcx+2h]
mov[rbp-38h],rdx
;------------------------------------------ CALCULATE NEW RED
fild dword[rbp-28h] ;Rot
fimul dword[rbp-8h] ;Factor
fistp dword[rbp-28h] ;Ergebnis
mov rax,[rbp-28h] ;Fehler!!! -> erhalte nicht den Wert von (Rot * Faktor)?!
;------------------------------------------ RETURN LABEL
@@:
;------------------------------------------ DEALLOCATE SPACE
add rsp,48h
;------------------------------------------ RESTORE OLD STACK
mov rsp,rbp
pop rbp
ret
Code: Alles auswählen
EnableExplicit
;PB v.6.52 x64 (Windows)
Import "nifDither.obj"
nifDitherRGB(*Pixel,*Exit,*Error,Factor.f)
EndImport
Structure RGB_STRUCT
RGB.a[3]
EndStructure
Global Pixel.RGB_STRUCT
Global Error.i
Global Factor.f
;Testwerte setzen:
Pixel\RGB[0] = 10
Pixel\RGB[1] = 20
Pixel\RGB[2] = 30
Factor = 2
Debug nifDitherRGB(@Pixel,@Pixel + 1,@Error,Factor)
-> Pixel\RGB[0] * Factor
Re: SetBits / GetBits gut genug?
Wenn Factor als Float deklariert wird hat r9 damit nichts zu tun. Als 4.Parameter wird Factor dann in xmm3 an die Procedure übergeben (Windows 64-Bit).
Andererseits sind doch die Parameter schon als Global deklariert, also warum die Übergabe-Klimmzüge (und der ganze Klimbim drumrum)?
Andererseits sind doch die Parameter schon als Global deklariert, also warum die Übergabe-Klimmzüge (und der ganze Klimbim drumrum)?
Re: SetBits / GetBits gut genug?
Helle hat geschrieben:Wenn Factor als Float deklariert wird hat r9 damit nichts zu tun. Als 4.Parameter wird Factor dann in xmm3 an die Procedure übergeben (Windows 64-Bit).
Andererseits sind doch die Parameter schon als Global deklariert, also warum die Übergabe-Klimmzüge (und der ganze Klimbim drumrum)?
Es war mir nicht bewusst das der Parameter als xmm3 übergeben wird.
Könnte der Parameter auch anders übergeben werden?
Die Parameter sind nur im Beispiel Global (später wird die Assembler Funktion für jedes Pixel mehrfach aufgerufen).
Ich hatte mich and den Assembler Code von diesem Macro gehalten:
Code: Alles auswählen
Macro MM(A,B)
(A * B)
EndMacro
MM(Pixel\RGB[0],1.33)
Code: Alles auswählen
lea rbp,[imagebase+5554]
push rbp
pop rbp
movzx r15,byte ptr [rbp+00]
mov [rsp-08],r15
fild qword ptr [rsp-08]
fmul qword ptr [imagebase+502C]
fistp qword ptr [rsp-08]
mov rax,[rsp-08]
ret
Wäre so etwas möglich?
Code: Alles auswählen
xmm0[Red,Green]
xmm1[Blue,0]
xmm3[Factor,Factor]
xmm0 * xmm3
xmm1 * xmm3
Re: SetBits / GetBits gut genug?
Hier ein zartes Prinzip-Beispiel (nur SSEx, kein AVX):
Code: Alles auswählen
Buffer1 = AllocateMemory(16) ;Werte-Buffer
Buffer2 = AllocateMemory(16) ;Zwischenspeicher
PokeB(Buffer1, 10) ;Beispiel-Werte
PokeB(Buffer1 + 1, 20)
PokeB(Buffer1 + 2, 30)
Factor.f = 0.4
!mov r8,[v_Buffer1] ;Register hier beliebig gewählt
!mov r9,[v_Buffer2]
!lea r10,[v_Factor]
!pshufd xmm2,[r10],0 ;Factor vervielfachen, bleibt unverändert
!pmovzxbd xmm0,[r8] ;4 Integer-Bytes zu 4 Integer-DWords erweitern (SSE4_1)
!cvtdq2ps xmm1,xmm0 ;4 Integer-DWords in 4 Floats konvertieren (SSE2)
!mulps xmm1,xmm2 ;4 Float-Multiplikationen
!cvtps2dq xmm0,xmm1 ;4 Floats in 4 integer-DWords konvertieren
!movups [r9],xmm0 ;4 integer-DWords in Buffer2 speichern
Debug PeekB(Buffer2) ;diese Einzel-Werte (als Bytes) können auch wieder in Buffer1 zurückgeschrieben werden; Buffer2 dadurch wieder verfügbar
Debug PeekB(Buffer2 + 4)
Debug PeekB(Buffer2 + 8)
Re: SetBits / GetBits gut genug?
Hier ohne Zwischenspeicher und mit Alignment-Beachtung von Factor (kann zur Sicherheit auch mit Buffer1 gemacht werden):
Code: Alles auswählen
Factor.f = 0.4
Buffer1 = AllocateMemory(16) ;Werte-Buffer
PokeB(Buffer1, 10) ;Beispiel-Werte
PokeB(Buffer1 + 1, 20)
PokeB(Buffer1 + 2, 30)
!mov r8,[v_Buffer1] ;Register hier beliebig gewählt
!lea r10,[v_Factor]
!movups xmm0,[r10] ;über Register wegen Alignment!
!pshufd xmm2,xmm0,0 ;Factor vervielfachen, bleibt unverändert
!pmovzxbd xmm0,[r8] ;4 Integer-Bytes zu 4 Integer-DWords erweitern (SSE4_1)
!cvtdq2ps xmm1,xmm0 ;4 Integer-DWords in 4 Floats konvertieren (SSE2)
!mulps xmm1,xmm2 ;4 Float-Multiplikationen
!cvtps2dq xmm0,xmm1 ;4 Floats in 4 integer-DWords konvertieren
!pextrb byte[r8],xmm0,0b
!pextrb byte[r8+1],xmm0,100b
!pextrb byte[r8+2],xmm0,1000b
Debug PeekB(Buffer1)
Debug PeekB(Buffer1 + 1)
Debug PeekB(Buffer1 + 2)
Re: SetBits / GetBits gut genug?
Vielen Dank für das genialen Beispiele
das es so tolle Instruktionen gibt
Re: SetBits / GetBits gut genug?
Ich muss den ersten Farbwert erst in ein Register übertragen da ich keine 4 Bytes auf einmal lesen darf.
Farbwert einlesen (*Pixel):
Wie bekomme ich nun an die Addresse von rax um diese and die SSE Instruktionen zu reichen?
Habe so versucht:
Farbwert einlesen (*Pixel):
Code: Alles auswählen
movzx rax,byte[rcx+2h]
movzx rbx,word[rcx]
shl rax,10h
or rax,rbx
Habe so versucht:
Code: Alles auswählen
mov [rsp + 8h],rax
pmovzxbd xmm0,[rsp + 8h]
movups [rdx],xmm0;<- überträgt nur das erste Byte!
Re: SetBits / GetBits gut genug?
Hmmm, wieso soll das nicht funzen?
Test:
Den Stack zu benutzen tue ich ohne ersichtlichen Vorteil selten, da ist schnell mal eine Gurke drin. Ich würde es so machen:
Test:
Code: Alles auswählen
Buffer1 = AllocateMemory(16) ;Werte-Buffer für Test
!mov rdx,[v_Buffer1]
!mov rax,102030h ;Testwert
!mov [rsp + 8h],rax ;rax auf Stack
!pmovzxbd xmm0,[rsp + 8h] ;4 Bytes vom Stack erweitern auf 4 DWords in xmm0
!movdqu [rdx],xmm0 ;die DWords rein in Buffer1, hier mal als Integers, movups tuts aber auch
;Test:
Debug Hex(PeekL(Buffer1)) ;DWord auslesen, Hex wegen optischen Vergleich
Debug Hex(PeekL(Buffer1 + 4));hier beachten, das DWords ausgelesen werden! Little Endian!
Debug Hex(PeekL(Buffer1 + 8))
Code: Alles auswählen
Buffer1 = AllocateMemory(16) ;Werte-Buffer
!mov rdx,[v_Buffer1]
!mov rax,405060h ;Testwert
!movq xmm1,rax ;rax als Quadword nach xmm1, "movd xmm1,eax" tuts genauso
!pmovzxbd xmm0,xmm1 ;4 (Low-)Bytes von rax in xmm1 erweitern auf 4 DWords in xmm0
!movdqu [rdx],xmm0 ;die DWords rein in Buffer1, hier mal als Integers, movups tuts aber auch
;Test:
Debug Hex(PeekL(Buffer1)) ;DWord auslesen, Hex wegen optischen Vergleich
Debug Hex(PeekL(Buffer1 + 4));hier beachten, das DWords ausgelesen werden! Little Endian!
Debug Hex(PeekL(Buffer1 + 8))
Re: SetBits / GetBits gut genug?
Danke @Helle für die Assembler Hilfe 
Nach längerem basteln will ich nun den aktuellen OBJ - Code und ein PureBasic Beispiel zeigen.
Das Dithering (Atkinson) funktioniert ganz gut allerdings belieben links und ganz unten im Bild unter Umständen Artefakte!
Die Ursache hierfür liegt noch im Dunkeln
Über weiter Ratschläge (vor allem zum Assembler Code) würde ich mich freuen
OBJ:
Beispiel:
Nach längerem basteln will ich nun den aktuellen OBJ - Code und ein PureBasic Beispiel zeigen.
Das Dithering (Atkinson) funktioniert ganz gut allerdings belieben links und ganz unten im Bild unter Umständen Artefakte!
Die Ursache hierfür liegt noch im Dunkeln
Über weiter Ratschläge (vor allem zum Assembler Code) würde ich mich freuen
OBJ:
Code: Alles auswählen
format MS64 COFF
;.......................................
public nifEncodeColor
public nifDither
;.......................................
section '.text' code readable executable
;.......................................
nifEncodeColor:;*Pixel,*Error
push rbp
mov rbp,rsp
sub rsp,8h
;------------------- GET PIXEL COLOR
movzx rax,byte[rcx+2h]
movzx r8,word[rcx]
shl rax,10h
or rax,r8
;------------------- STORE PIXEL COLOR ADDRESS
mov [rsp+8h],rax
;------------------- RESET ORIGINAL PIXEL COLOR
mov byte[rcx],0h
mov word[rcx+1h],0h
;------------------- CALCULATE & SET NEW PIXEL COLOR
cmp byte[rsp+8h],7Fh
ja @f
mov byte[rcx],0FFh
@@:
cmp byte[rsp+9h],7Fh
ja @f
mov byte[rcx+1h],0FFh
@@:
cmp byte[rsp+0Ah],7Fh
ja @f
mov byte[rcx+2h],0FFh
@@:
;------------------- CALCULATE ERROR
mov al,byte[rsp+8h]
sub al,byte[rcx]
mov byte[rdx],al
mov al,byte[rsp+9h]
sub al,byte[rcx+1h]
mov byte[rdx+1h],al
mov al,byte[rsp+0Ah]
sub al,byte[rcx+2h]
mov byte[rdx+2h],al
add rsp,8h
mov rsp,rbp
pop rbp
ret
nifDither:;*Pixel,*Exit,*Error,*Factor - Dank Helle :)
cmp rcx,rdx
ja @f
push rbp
mov rbp,rsp
sub rsp,8h
movzx rax,byte[rcx+2h]
movzx rdx,word[rcx]
shl rax,10h
or rax,rdx
mov [rsp+8h],rax
pmovzxbd xmm0,[r8]
cvtdq2ps xmm1,xmm0
pmovzxbd xmm0,[rsp+8h]
cvtdq2ps xmm3,xmm0
movups xmm0,[r9]
pshufd xmm2,xmm0,0h
mulps xmm1,xmm2
addps xmm1,xmm3
cvtps2dq xmm0,xmm1
pextrb byte[rcx],xmm0,0b
pextrb byte[rcx+1h],xmm0,100b
pextrb byte[rcx+2h],xmm0,1000b
add rsp,8h
mov rsp,rbp
pop rbp
@@:
ret
Code: Alles auswählen
;PureBasic v.6.52 x64
EnableExplicit
UseJPEGImageDecoder();Unterstützung für JPEG und PNG!
UseJPEG2000ImageDecoder()
UsePNGImageDecoder()
Import "nifDither.obj"
nifEncodeColor.i(*Pixel,*Error)
nifDither.i(*Pixel,*Exit,*Error,*Factor)
EndImport
Structure BITMAP_STRUCT
bmType.l
bmWidth.l
bmHeight.l
bmWidthBytes.l
bmPlanes.w
bmBitsPixel.w
Alignment.b[4]
*bmBits
PixelSize.i
Bytes.i
Exit.i
EndStructure
Structure IMAGE_STRUCT
Id.i
Handle.i
Bitmap.BITMAP_STRUCT
EndStructure
Procedure.i nifFree(*nif.IMAGE_STRUCT)
With *nif
If IsImage(\Id)
FreeImage(\Id)
EndIf
FreeStructure(*nif)
EndWith
EndProcedure
Procedure.i nifBitmap(*nif.IMAGE_STRUCT)
With *nif
If \Handle
If GetObject_(\Handle,SizeOf(BITMAP),@\Bitmap)
\Bitmap\PixelSize = \Bitmap\bmBitsPixel / 8
\Bitmap\Bytes = \Bitmap\bmWidthBytes * \Bitmap\bmHeight
\Bitmap\Exit = \Bitmap\bmBits + \Bitmap\Bytes - \Bitmap\PixelSize
ProcedureReturn #True
EndIf
EndIf
EndWith
EndProcedure
Procedure.i nifEncode(*nif.IMAGE_STRUCT)
Protected ImageX.i
Protected ImageY.i
Protected *Scanline
Protected *Pixel
Protected Index.i
Protected Factor1.f
Protected Factor2.f
With *nif
If \Bitmap\bmBitsPixel = 24
Factor1 = 0.375
Factor2 = 0.125
For ImageY = 0 To \Bitmap\bmHeight - 1
*Scanline = \Bitmap\bmBits +(ImageY * \Bitmap\bmWidthBytes)
For ImageX = 0 To \Bitmap\bmWidth - 1
*Pixel = *Scanline + (ImageX * \Bitmap\PixelSize)
nifEncodeColor(*Pixel,@Error)
nifDither(*Pixel + \Bitmap\PixelSize,\Bitmap\Exit,@Error,@Factor1);Atkinson
nifDither(*Pixel + \Bitmap\bmWidthBytes + \Bitmap\PixelSize,\Bitmap\Exit,@Error,@Factor2)
nifDither(*Pixel + \Bitmap\PixelSize + \Bitmap\PixelSize,\Bitmap\Exit,@Error,@Factor2)
nifDither(*Pixel + \Bitmap\bmWidthBytes,\Bitmap\Exit,@Error,@Factor2)
nifDither(*Pixel + \Bitmap\bmWidthBytes - \Bitmap\PixelSize,\Bitmap\Exit,@Error,@Factor2)
nifDither(*Pixel + \Bitmap\bmWidthBytes + \Bitmap\bmWidthBytes,\Bitmap\Exit,@Error,@Factor2)
Next
Next
ProcedureReturn #True
Else
;Bild mit Alpha!
EndIf
EndWith
EndProcedure
Procedure.i nifHandle(*nif.IMAGE_STRUCT)
With *nif
ProcedureReturn \Handle
EndWith
EndProcedure
Procedure.i nifLoadImage(File.s)
Protected *nif.IMAGE_STRUCT
Protected Timer.q
*nif = AllocateStructure(IMAGE_STRUCT)
If *nif
With *nif
\Id = LoadImage(#PB_Any,File)
If \Id
\Handle = ImageID(\Id)
If nifBitmap(*nif)
Timer = ElapsedMilliseconds()
If nifEncode(*nif)
Timer = ElapsedMilliseconds() - Timer
MessageRequester("","Timer: " + Str(Timer))
ProcedureReturn *nif
EndIf
EndIf
EndIf
nifFree(*nif)
EndWith
EndIf
EndProcedure
Procedure.i nifSaveBitmap(*nif.IMAGE_STRUCT,File.s)
With *nif
ProcedureReturn SaveImage(\Id,File,#PB_ImagePlugin_BMP,#Null,\Bitmap\bmBitsPixel)
EndWith
EndProcedure
Global Image.i
Global File.s
File = "XYZ";<- ÄNDERN!!!
Image = nifLoadImage(File)
If Image
;nifSaveBitmap(Image,"converted_" + File)
If OpenWindow(0,0,0,800,580,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
If StartVectorDrawing(WindowVectorOutput(0))
MovePathCursor(0,0)
DrawVectorImage(nifHandle(Image),$FF,800,580)
EndIf
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
CloseWindow(0)
EndIf
nifFree(Image)
EndIf
End

