rotation d'image

Pour discuter de l'assembleur
manababel
Messages : 136
Inscription : jeu. 14/mai/2020 7:40

rotation d'image

Message par manababel »

Se programme permet de faire une rotation d'une image de 0 à 360 degrés.

Code : Tout sélectionner

EnableExplicit

Global Dim Reg_memory.q(4*344)

;-------------------------------------------------------------------
; sauvegarde de registres
Macro Save_reg()
  Protected s.q
  s=@reg_memory()
  EnableASM
  !mov rax,[p.v_s]
  !mov [rax+000],rbx
  !mov [rax+008],rcx ;
  !mov [rax+016],rdx ;
  !mov [rax+024],rsi
  !mov [rax+032],rdi
  !mov [rax+040],r8 ;
  !mov [rax+048],r9 ;
  !mov [rax+056],r10
  !mov [rax+064],r11
  !mov [rax+072],r12
  !mov [rax+080],r13
  !mov [rax+088],r14
  !mov [rax+096],r15

  !movdqu [rax+104],xmm0 ;
  !movdqu [rax+120],xmm1 ;
  !movdqu [rax+136],xmm2 ;
  !movdqu [rax+152],xmm3 ;
  !movdqu [rax+168],xmm4
  !movdqu [rax+184],xmm5
  !movdqu [rax+200],xmm6
  !movdqu [rax+216],xmm7
  !movdqu [rax+232],xmm8
  !movdqu [rax+248],xmm9
  !movdqu [rax+264],xmm10
  !movdqu [rax+280],xmm11
  !movdqu [rax+296],xmm12
  !movdqu [rax+312],xmm13
  !movdqu [rax+328],xmm14
  !movdqu [rax+344],xmm15
  DisableASM
EndMacro

Macro Rest_Reg()
; restore les registres
  s=@reg_memory()
  EnableASM
  !mov rax,[p.v_s]
  !mov rbx,[rax+000]
  !mov rcx,[rax+008]
  !mov rdx,[rax+016]
  !mov rsi,[rax+024]
  !mov rdi,[rax+032]
  !mov r8,[rax+040]
  !mov r9,[rax+048]
  !mov r10,[rax+056]
  !mov r11,[rax+064]
  !mov r12,[rax+072]
  !mov r13,[rax+080]
  !mov r14,[rax+088]
  !mov r15,[rax+096]

  !movdqu xmm0,[rax+104] ;
  !movdqu xmm1,[rax+120] ;
  !movdqu xmm2,[rax+136] ;
  !movdqu xmm3,[rax+152] ;
  !movdqu xmm4,[rax+168]
  !movdqu xmm5,[rax+184]
  !movdqu xmm6,[rax+200]
  !movdqu xmm7,[rax+216]
  !movdqu xmm8,[rax+232]
  !movdqu xmm9,[rax+248]
  !movdqu xmm10,[rax+264]
  !movdqu xmm11,[rax+280]
  !movdqu xmm12,[rax+296]
  !movdqu xmm13,[rax+312]
  !movdqu xmm14,[rax+328]
  !movdqu xmm15,[rax+344]
  DisableASM

EndMacro



; charge une image et la convertie en 32bit
;-------------------------------------------------------------------
Procedure load_image(nom,file$)
  Protected source_p , cible_p , s.q
  Protected lg.q , ht.q , taille.q , depth.q
 
  LoadImage(nom,file$)
  If Not IsImage(nom) : ProcedureReturn 0 : EndIf
   
  StartDrawing(ImageOutput(nom))
  source_p = DrawingBuffer()
  ht = ImageHeight(nom)
  lg = ImageWidth(nom)
  Depth=OutputDepth()
  StopDrawing()
 
  If Depth=24
    taille=lg*ht
    cible_p=AllocateMemory(taille*4)
    Dim save.q(4)
    s=@save()
    EnableASM
      !mov rax,[p.v_s]
      !mov [rax],rcx
      !mov [rax+8],rdx
      !mov [rax+16],r8
      !mov rcx,[p.v_source_p]
      !mov rdx,[p.v_cible_p]
      !mov r8,[p.v_taille]
      !sub r8,1 ; <---------------- ????
      !copy_boucle24:
        !mov eax,[rcx]     
        !mov [rdx],eax
        !add rcx,3
        !add rdx,4
        !dec r8
       !jnz copy_boucle24
      !mov rax,[p.v_s]
      !mov rcx,[rax]
      !mov rdx, [rax+8]
      !mov r8,[rax+16]
    DisableASM
    FreeArray(save())
   
    FreeImage(nom) ; supprime l'image 24bits
    CreateImage(nom,lg,ht,32)
    StartDrawing(ImageOutput(nom))
    source_p = DrawingBuffer()
    StopDrawing()
    CopyMemory( cible_p , source_p , taille*4 )
    FreeMemory(cible_p)
  EndIf
  ProcedureReturn 1
EndProcedure




; partie du programme à modifier pour adapter se programme au votre
; convertie les "IDs" des images en pointer d'adresse
; test si les images sont en 32bits et de la meme taille
;-------------------------------------------------------------------

Macro sp(source,cible)
  Protected Depth.q , lg.q , ht.q , lg1.q , ht1.q , taille.q
  Protected cible_p.q , source_p.q
 
  StartDrawing(ImageOutput(cible))
  cible_p = DrawingBuffer()
  ht1 = ImageHeight(cible)
  lg1 = ImageWidth(cible)
  Depth=OutputDepth()
  StopDrawing()
  If depth<>32 : ProcedureReturn : EndIf
 
  StartDrawing(ImageOutput(source))
  source_p = DrawingBuffer()
  ht = ImageHeight(source)
  lg = ImageWidth(source)
  Depth=OutputDepth()
  StopDrawing()
  If depth<>32 : ProcedureReturn : EndIf
 
  If lg<>lg1 Or ht<>ht1 : ProcedureReturn : EndIf
 
EndMacro

;-------------------------------------------------------------------
;--version purebasic
Procedure Filter_Rotate_pb(source,cible,angle)
  Protected degres.f , c1.f , s1.f , x3.f , y3.f
  Protected x.l , y.l, xx.l , yy.l , var.l
  Protected pos.q
  
  sp(source,cible)
  
  degres.f=angle*#PI/180
  c1.f=Cos(degres)
  s1.f=Sin(degres)
  x3.f=lg/2
  y3.f=ht/2 
  
  For y=0 To ht-1
    pos=(cible_p+(lg*y)*4)
    For x=0 To lg-1    
      xx.l=x3+ ((x-x3) * c1) + (y-y3)* s1
      yy.l=y3- ((x-x3) * s1) + (y-y3)* c1
      If (xx<0) Or (xx>lg-1) Or (yy<0) Or (yy>ht-1)
        PokeL(pos+x*4,0) ; fond noir
      Else
        var=PeekL(source_p+(yy*lg*4)+xx*4)
        PokeL(pos+x*4,var)
      EndIf     
    Next
  Next

EndProcedure

;-------------------------------------------------------------------
;--version asm
Procedure Filter_Rotate_asm(source,cible,angle)
    Save_reg()
  Protected degres.f , c1.f , s1.f , x3.f , y3.f
  sp(source,cible)
  
  degres=angle*#PI/180
  c1=Cos(degres)
  s1=Sin(degres)
  x3=lg/2
  y3=ht/2 
  
  !INSERTPS xmm1,[p.v_x3],$10 ; x3
  !INSERTPS xmm1,[p.v_y3],$00 ; y3
  ; xmm1 = x3 y3
  !INSERTPS xmm2,[p.v_c1],$10 ; c1
  !INSERTPS xmm2,[p.v_s1],$00 ; s1
  ; xmm2 = c1 s1
  !INSERTPS xmm3,[p.v_s1],$10 ; s1
  !INSERTPS xmm3,[p.v_c1],$00 ; c1
  ; xmm3 = s1 c1
  
  !xor r11,r11
  !xor r10,r10 ; For y=0 To ht-1
  !boucle_y:    
    !xor r9,r9 ; For x=0 To lg-1 
    !boucle_x:
      ;xx=  x3 + ( ( x - x3 ) * c1 )    +   ( ( y - y3 ) * s1 )
      ;yy=  y3 - ( ( x - x3 ) * s1 )    +   ( ( y - y3 ) * c1 )
      !movq xmm4,r9;[p.v_x]
      !CVTDQ2PS xmm4,xmm4 ; xmm4 = float(x)
      !movq xmm5,r10;[p.v_y]
      !CVTDQ2PS xmm5,xmm5 ; xmm5 = float(y)
      !subss xmm4,[p.v_x3]; (x-x3)
      !subss xmm5,[p.v_y3]; (y-y3)
      !VBROADCASTSS xmm4,xmm4 ; (x-x3)         (x-x3)
      !VBROADCASTSS xmm5,xmm5 ; (y-y3)         (y-y3)
      !mulps xmm4,xmm2 ;        (x-x3)*c1      (x-x3)*s1
      !mulps xmm5,xmm3 ;        (y-y3)*s1      (y-y3)*c1
      !ADDSUBPS xmm4,xmm5 ; (x-x3)*c1+(y-y3)*s1       (x-x3)*s1-(y-y3)*c1
      !movups xmm5,xmm1
      !ADDSUBPS xmm5,xmm4 ; x3+(x-x3)*c1+(y-y3)*s1       y3-(x-x3)*s1-(y-y3)*c1
      !CVTPS2DQ xmm5,xmm5 ; xmm5 = int(xmm5)
      
      !xor rax,rax
      !PEXTRD eax,xmm5,0
      !mov r13,rax ; r13 = yy
      !xor rax,rax
      !PEXTRD eax,xmm5,1
      !mov r12,rax ; r12 = xx
    
      !mov ecx,0 ; var = 0 = couleur  noir
      
      !cmp r12,[p.v_lg] ; if xx>=lg : goto 'saut'
      !jge saut
      ;!cmp r12,0 ; if xx<0 : goto 'saut'
      ;!jl saut
      !cmp r13,[p.v_ht]  ; if yy>=ht : goto 'saut'
      !jge saut
      ;!cmp r13,0 ; if yy<0 : goto 'saut'
      ;!jl saut
      
        !mov r8,r13;[p.v_yy] ;var = PeekL(source_p+((yy*lg)+xx)*4)
        !iMUL r8,[p.v_lg]
        !add r8,r12;[p.v_xx]
        !shl r8,2
        !add r8,[p.v_source_p]
        !mov ecx,[r8]
        
      !saut:       
      
      !mov rdx,r11 ; pos=(cible_p+(lg*y)*4)
      !shl rdx,2
      !add rdx,[p.v_cible_p]
      !mov rax,r9 ; PokeL(pos+x*4,var)
      !shl rax,2
      !add rax,rdx
      !mov [rax],ecx
      
    !inc r9 ; x=x-1
    !cmp r9,[p.v_lg]
    !jb boucle_x ; Next x
    
  !add r11,[p.v_lg] ; 'lg*y'
  !inc r10 ; xyx+1
  !cmp r10,[p.v_ht]
  !jb boucle_y ; next y

  Rest_Reg()
EndProcedure

;-------------------------------------------------------------------

UseJPEGImageDecoder()
UsePNGImageDecoder()
Global imgx=1200
Global imgy=800


If OpenWindow(0, 0, 0, imgx, imgy+16, "Rotate", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  Define source.q , cible.q , t.q , file$ , i , angle.l , mem_angle.l 
 
   file$ = OpenFileRequester("Image","","",0)
   source=10
   cible=20
   
   If Not Load_Image(source,file$) ; <- commande differente de "LOADIMAGE"
     MessageRequester("load_image","erreur de chargement",#PB_MessageRequester_Ok | #PB_MessageRequester_Error)
     End
   EndIf
   
   ScrollBarGadget(1, 0, 0, 1200, 16, 0, 360, imgx/360 )  
   
   ResizeImage(source,imgx,imgy,#PB_Image_Smooth)
   
   CreateImage(cible,imgx,imgy,32) ; l'image doit entre en mode 32bits
   
   mem_angle=1
   Repeat 
     angle=GetGadgetState(1)
     If angle<>mem_angle
       t=ElapsedMilliseconds()
       angle=GetGadgetState(1)
         Filter_Rotate_pb(source,cible,angle) ; <--- par defaut , version purebasic
       t=ElapsedMilliseconds()-t
       StartDrawing(WindowOutput(0))
       DrawImage(ImageID(cible),0,16)
       DrawText(5,5+16,Str(t))
       StopDrawing()
       mem_angle = angle
     EndIf
     
   Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf


Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: rotation d'image

Message par falsam »

Très bien ce code. Merci :wink:
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
Guillot
Messages : 527
Inscription : jeu. 25/juin/2015 16:18

Re: rotation d'image

Message par Guillot »

tu peux aussi écrire ta fonction comme ça:
je pense que c'est plus rapide, juste 2 additions par pixel (et 2 conversions en int)

Code : Tout sélectionner

Procedure Filter_Rotate_pb(source,cible,angle)
    Protected degres.f , c1.f , s1.f , x3.f , y3.f
    Protected x.l , y.l, var.l
    Protected.f xx , yy
    Protected pos.q
    
    sp(source,cible)
    
    degres.f=angle*#PI/180
    c1.f=Cos(degres)
    s1.f=Sin(degres)
    x3.f=lg/2
    y3.f=ht/2
    
    For y=0 To ht-1
        pos=(cible_p+(lg*y)*4)
        xx=x3 -x3 * c1 + (y-y3)* s1
        yy=y3 +x3 * s1 + (y-y3)* c1
        For x=0 To lg-1   
            If (xx<0) Or (xx>lg-1) Or (yy<0) Or (yy>ht-1)
                PokeL(pos+x*4,0) ; fond noir
            Else
                var=PeekL(source_p+(Int(yy)*lg*4)+Int(xx)*4)
                PokeL(pos+x*4,var)
            EndIf     
            xx+c1
            yy-s1
        Next
    Next
EndProcedure
manababel
Messages : 136
Inscription : jeu. 14/mai/2020 7:40

Re: rotation d'image

Message par manababel »

Bizarment en purebasic , il n'y a pas de différence de performance.
mais en Asm il y plus de 30% de différence.
merci pour le code.

Code : Tout sélectionner

Procedure Filter_Rotate_pb(source,cible,angle)
    Protected degres.f , c1.f , s1.f , x2.f , y2.f, x3.f , y3.f
    Protected x.l , y.l, var.l
    Protected.f xx , yy
    Protected pos.q
   
    sp(source,cible)
   
    degres.f=angle*#PI/180
    c1.f=Cos(degres)
    s1.f=Sin(degres)
    x3.f=lg/2
    y3.f=ht/2
    x2.f=(x3 * c1)
    y2.f=(x3 * s1)
    
    For y=0 To ht-1
        pos=(cible_p+(lg*y)*4)
        xx=x3 - (x2 - ((y-y3)* s1))
        yy=y3 + (y2 + ((y-y3)* c1))
        For x=0 To lg-1   
            If (xx<0) Or (xx>lg-1) Or (yy<0) Or (yy>ht-1)
                PokeL(pos+x*4,0) ; fond noir
            Else
                var=PeekL(source_p+(Int(yy)*lg*4)+Int(xx)*4)
                PokeL(pos+x*4,var)
            EndIf     
            xx+c1
            yy-s1
        Next
    Next
EndProcedure

Code : Tout sélectionner

Procedure Filter_Rotate_asm(source,cible,angle)
    Save_reg()
  Protected degres.f , c1.f , s1.f , x2.f , y2.f , x3.f , y3.f
  sp(source,cible)
 
  degres=angle*#PI/180
  c1=Cos(degres)
  s1=Sin(degres)
  x3=lg/2
  y3=ht/2
  x2.f=(x3 * c1)
  y2.f=(x3 * s1)
  
  !xor r15,r15
  !xor r14,r14
  
  !movss xmm12,[p.v_c1]
  !movss xmm13,[p.v_s1]

  !INSERTPS xmm1,[p.v_x3],$00 ; x3
  !INSERTPS xmm1,[p.v_y3],$10 ; y3
  ; xmm1 = y3 x3
  !INSERTPS xmm2,[p.v_s1],$00 ; s1
  !INSERTPS xmm2,[p.v_c1],$10 ; c1
  ; xmm2 = c1 s1
  !INSERTPS xmm3,[p.v_x2],$00 ; x2
  !INSERTPS xmm3,[p.v_y2],$10 ; y2
  ; xmm3 = y2 x2
 
  !xor r11,r11
  !xor r10,r10 ; For y=0 To ht-1
  !boucle_y:   
    ;xx=x3 - (x2 - ((y-y3)* s1))
    ;yy=y3 + (y2 + ((y-y3)* c1))
    !movq xmm4,r10;[p.v_y]
    !CVTDQ2PS xmm4,xmm4 ; xmm4 = float(y)  
    !subss xmm4,[p.v_y3]; (y-y3)
    !INSERTPS xmm4,xmm4,$10 ; (y-y3)         (y-y3)
    !mulps xmm4,xmm2 ;        (y-y3)*c1      (y-y3)*s1
    !movups xmm5,xmm3 ;          y2             x2
    !ADDSUBPS xmm5,xmm4 ;    y2+((y-y3)*c1)   x2-((y-y3)*s1)
    !movups xmm4,xmm1  ;           y3               x3
    !ADDSUBPS xmm4,xmm5 ;  y3+(y2+(y-y3)*c1)    x3-(x2-(y-y3)*s1)
       
    !INSERTPS xmm6,xmm4,$10
    !INSERTPS xmm6,xmm4,$40
    
    !xor r9,r9 ; For x=0 To lg-1    
    !boucle_x:  
    
      !CVTPS2DQ xmm5,xmm6 ; xmm5 = int(xmm6) 
      !xor rax,rax
      !PEXTRD eax,xmm5,0
      !mov r13,rax ; r13 = yy
      !xor rax,rax
      !PEXTRD eax,xmm5,1
      !mov r12,rax ; r12 = xx
    
      !mov ecx,0 ; var = 0 = couleur  noir
      !cmp r12,[p.v_lg] ; if xx>=lg : goto 'saut'
      !jge saut
      !cmp r12,0 ; if xx<0 : goto 'saut'
      !jl saut
      !cmp r13,[p.v_ht]  ; if yy>=ht : goto 'saut'
      !jge saut
      !cmp r13,0 ; if yy<0 : goto 'saut'
      !jl saut
        !mov r8,r13;[p.v_yy] ;var = PeekL(source_p+((yy*lg)+xx)*4)
        !iMUL r8,[p.v_lg]
        !add r8,r12;[p.v_xx]
        !shl r8,2
        !add r8,[p.v_source_p]
        !mov ecx,[r8]
      !saut:       
      !mov rdx,r11 ; pos=(cible_p+(lg*y)*4)
      !shl rdx,2
      !add rdx,[p.v_cible_p]
      !mov rax,r9 ; PokeL(pos+x*4,var)
      !shl rax,2
      !add rax,rdx
      !mov [rax],ecx
      
      !ADDSUBPS xmm6,xmm2
      
    !inc r9 ; x=x+1
    !cmp r9,[p.v_lg]
    !jb boucle_x ; Next x
   
  !add r11,[p.v_lg] ; 'lg*y'
  !inc r10 ; y=y+1
  !cmp r10,[p.v_ht]
  !jb boucle_y ; next y

  Rest_Reg()
EndProcedure
Répondre