Mandelbrot viewer

Applications, Games, Tools, User libs and useful stuff coded in PureBasic
User avatar
pf shadoko
Enthusiast
Enthusiast
Posts: 290
Joined: Thu Jul 09, 2015 9:07 am

Mandelbrot viewer

Post by pf shadoko »

hi everyone

a small viewer of the Mandelbrot function
it is very fast, calculations are made in ASM (thanks Manababel! (french forum)
it is multithreaded

by pressing [F1] you will even get a guided tour!

remove the debugger!!
and activate the management of treads in the compilation options (not necessary at home??)

Code: Select all

EnableExplicit

Global limit=255,ex=1280,ey=720,     i,x,y,z,b,dx,dy,pass=-1,cpt=4,t
Global.d apx,px, apy,py,ascale,scale

Global Dim pal.l(limit)
Global Dim Bmp.l(ey - 1, ex - 1)

Global ndt=CountCPUs(#PB_System_ProcessCPUs )
Global Dim Thread(ndt)

Procedure ColorBlend(color1.l, color2.l, blend.f)
    Protected r.w,g.w,b.w,a.w
    r=  Red(color1) + (Red(color2)     - Red(color1)) * blend
    g=Green(color1) + (Green(color2) - Green(color1)) * blend
    b= Blue(color1) + (Blue(color2) -   Blue(color1)) * blend
    a=Alpha(color1) + (Alpha(color2) - Alpha(color1)) * blend
    ProcedureReturn  RGBA(r,g,b,a)
EndProcedure

Procedure InitPalette(n=16,Cont=0)
    Protected i,j,c1,c2
    c2=Random($ffffff)
    For j = 0 To limit/n
        If Cont:c1=c2:Else:c1=Random($ffffff):EndIf
        c2=Random($ffffff)
        For i=0 To n-1
            pal(j*n+i) =ColorBlend(c1,c2, i/ n) | $ff000000
        Next
    Next
    pal(limit) = $ff000000
EndProcedure

Procedure mandelbrotx4(a.d,b.d,scale.d,Array col.q(1))
    Protected cp.q,fo.d,add.q,     i,t,c
    Protected infinity.f=4
    Dim tab.d(4)
    cp=limit
    fo=infinity
    add=1
    For i=0 To 3
        tab(i)=a
        a+scale
    Next

    t=@tab()
    c=@col()
    !mov rdx,[p.v_t]
    !VPBROADCASTQ ymm8,[p.v_add] ;1  1  1  1
    !VBROADCASTSD ymm7,[p.v_fo] ; 4  4  4  4
    !vmovupd ymm0,[rdx] ;         a1 a2 a3 a4
    !VBROADCASTSD ymm1,[p.v_b] ;  b  b  b  b
    !vmovupd ymm2,ymm0 ; c=a
    !vmovupd ymm3,ymm1 ; d=b
    !vpxor ymm9,ymm9,ymm9
   
    !xor rax,rax
    !boucle:
   
    !vmovupd ymm4,ymm0
    !vmovupd ymm5,ymm1
    !vmulpd ymm4,ymm4,ymm4 ; aa = a * a
    !vmulpd ymm5,ymm5,ymm5 ; bb = b * b
   
    !vmovupd ymm6,ymm4
    !vaddpd ymm6,ymm6,ymm5
   
    ;If (aa + bb) > 4.0:Goto fin:EndIf
    !vcmpltpd ymm6,ymm6,ymm7
    !vmovmskpd rcx,ymm6
    !vandpd  ymm6,ymm6,ymm8 ; and 1
    !vpaddq ymm9,ymm9,ymm6  ; add 1
    !Or rcx,rcx
    !jz fin
   
    ;x1 = 2 * x0 * x1 + x3
    !vmulpd ymm1,ymm1,ymm0 ; b*a
    !vaddpd ymm1,ymm1,ymm1 ; (a*b)*2
    !vaddpd ymm1,ymm1,ymm3 ; (a*b*2)+d
   
    ;x0 = x4 - x5 + c
    !vmovupd ymm0,ymm4 ; a = aa
    !vsubpd ymm0,ymm0,ymm5 ; a = aa - bb
    !vaddpd ymm0,ymm0,ymm2 ;  a = aa - bb + c
   
    !inc rax
    !cmp rax,[p.v_cp]
    !jb boucle
   
    !fin:
   
    !mov rdx,[p.v_c]
    !vMOVDQU [rdx],ymm9
   
    !VZEROALL
   
EndProcedure

Procedure mandelbrot(num)
    Protected i,j,di,dj,jdeb,jfin  ,x.d,y.d
    Dim col.q(4)
    
    jdeb=ey/ndt*num
    jfin=ey/ndt*(num+1)
    di=pass & 1
    dj=pass >>1
    For j=jdeb+dj To jfin-1 Step 2
        y=py+(j -ey/2)*scale
        x=px+(di-ex/2)*scale
        For i=di To ex-1 Step 8
            mandelbrotx4(x, y,scale*2,col())
            bmp(j,i+0)=pal(col(0))
            bmp(j,i+2)=pal(col(1))
            bmp(j,i+4)=pal(col(2))
            bmp(j,i+6)=pal(col(3))
            x+scale*8
        Next
    Next
EndProcedure

InitSprite()
InitKeyboard()
InitMouse()
OpenWindow(0, 0, 0,ex,ey, " Mandelbrot - Use mouse + wheel - LMB to change colors - [F1] Animation (clic to stop) - [Esc] Quit",#PB_Window_ScreenCentered):OpenWindowedScreen(WindowID(0), 0, 0, ex, ey)
;OpenScreen(ex,ey,32,"")

InitPalette()
scale=2/ey

Structure d3
    x.d
    y.d
    z.d
EndStructure

Define auto=0,n,speed.f=0.01,ncible=-1
Dim cible.d3(100)
Macro defcible(vx,vy,vz)
    ncible+1
    cible(ncible)\x=vx
    cible(ncible)\y=vy
    cible(ncible)\z=vz
EndMacro

defcible(0,0,scale)
defcible(-1.74824670606330,-0.00000929287120,0.0000000000004)
defcible(-1.47371049186618,-0.00118606043680,0.00000000000402)
defcible(-0.10494709460288,0.92785703871758,0.00000000000002)
defcible(-0.17030719754610,-1.04455558192402,0.00000000000002)
defcible(-1.02351647109090,-0.28038897116474,0.000000000000003)
defcible(-1.24608830915113,-0.32550803613228,0.000000000000072)
defcible(-1.25403231646337,0.38483487689992,0.000000000000183)
defcible(-1.24165790231311,0.32354681010716,0.00000000000001)
defcible(0.39271500274068,-0.36734653571715,0.000000000000044)
defcible(-1.48126951978746,-0.00269131747118,0.00000000000004)
defcible(-1.99909584429894,-0.00000007963938,0.00000000000090)
n=Random(ncible,1)
CreateSprite(0,32,32):StartDrawing(SpriteOutput(0)):LineXY(0,15,31,15,$ffffffff):LineXY(15,0,15,31,$ffffffff):StopDrawing()
MouseLocate(ex/2,ey/2)
Repeat  
    WindowEvent()
    ExamineMouse()
    ExamineKeyboard()
    If MouseButton(2):InitPalette():cpt=4:EndIf 
    If MouseButton(3):SetClipboardText("defcible("+StrD(px,14)+","+StrD(py,14)+","+StrD(scale,14)+")"):End:EndIf 
    ascale=scale
    apx=px
    apy=py
    If auto
        If Abs(Log(scale)-Log(cible(n)\z))<0.1:If n:n=0:Else:n=Random(ncible,1):InitPalette():EndIf:Debug n:EndIf
        px+(cible(n)\x-px)*speed*1.1
        py+(cible(n)\y-py)*speed*1.1
        scale+(cible(n)\z-scale)*speed
        If MouseButton(1):auto=0:EndIf
    Else
        x=MouseX()
        y=MouseY()
        scale=scale*(1-0.1*MouseWheel())
        px-(x-ex/2)*(scale-ascale)
        py-(y-ey/2)*(scale-ascale)
        If MouseButton(1):px-MouseDeltaX()*scale:py-MouseDeltaY()*scale:EndIf         
        If KeyboardReleased(#PB_Key_F1):auto=1:scale=cible(n)\z:EndIf
    EndIf
    If ascale<>scale Or apx<>px Or apy<>py:cpt=4:EndIf
    If cpt
        cpt-1
        pass=(pass+1) & 3
;         t=ElapsedMilliseconds()
        For i=0 To ndt-1:Thread(i)=CreateThread(@mandelbrot(),i):Next
        For i=0 To ndt-1:If Thread(i) : WaitThread(thread(i)):EndIf:Next
        ;ndt=1:mandelbrot(0)
        ;t=ElapsedMilliseconds()-t
    EndIf
    StartDrawing(ScreenOutput())
    CopyMemory(@bmp(0,0),DrawingBuffer(),ex*ey*4)
    DrawingMode(#PB_2DDrawing_Transparent )
    DrawText(10,10,"Scale  " + StrD(scale,14))
    DrawText(10,30,"X  "+StrD(px,14))
    DrawText(10,50,"Y  "+StrD(py,14))
    ;DrawText(10,70,Str(t))
    StopDrawing()
    DisplayTransparentSprite(0,x-15,y-15)
    FlipBuffers()
Until KeyboardReleased(#PB_Key_Escape)
User avatar
STARGÅTE
Addict
Addict
Posts: 2085
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: Mandelbrot viewer

Post by STARGÅTE »

Nice small code.
How can I increase the iteration limit? Many areas look unfinished.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Mandelbrot viewer

Post by davido »

@pf shadoko,

Very nice. Thankyou. :D
DE AA EB
User avatar
NicTheQuick
Addict
Addict
Posts: 1226
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Mandelbrot viewer

Post by NicTheQuick »

I've got an illegal instruction error. On every run the position is somewhere else.
In German it says: "[ERROR] Illegale Anweisung. (Ausführen von binären Daten?)"
Freely translated to: "[ERROR] Illegal instruction. (Exexution of binary data?)"

Are there maybe assembler instructions which my CPU is too old for? It's an Intel Core i7-3820QM wit the following flags:
fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm cpuid_fault epb pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms xsaveopt dtherm ida arat pln pts md_clear flush_l1d
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
Paul
PureBasic Expert
PureBasic Expert
Posts: 1252
Joined: Fri Apr 25, 2003 4:34 pm
Location: Canada
Contact:

Re: Mandelbrot viewer

Post by Paul »

NicTheQuick wrote:I've got an illegal instruction error. On every run the position is somewhere else.
Looks like it must be compiled with PB x64 and debugger off.
Image Image
BarryG
Addict
Addict
Posts: 3320
Joined: Thu Apr 18, 2019 8:17 am

Re: Mandelbrot viewer

Post by BarryG »

Looks like Paul is right. This is PureBasic 32-bit version on Win 10:

Code: Select all

---------------------------
PureBasic - Assembler error
---------------------------
PureBasic.asm [1501]:
mov rdx,[p.v_t]
error: illegal instruction.
---------------------------
OK   
---------------------------
User avatar
NicTheQuick
Addict
Addict
Posts: 1226
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Mandelbrot viewer

Post by NicTheQuick »

I never use 32 bit because I have a 64 Bit Linux. But I did use the Debugger. I just tried it without the debugger but it also quits immediately.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
Mindphazer
Enthusiast
Enthusiast
Posts: 341
Joined: Mon Sep 10, 2012 10:41 am
Location: Savoie

Re: Mandelbrot viewer

Post by Mindphazer »

Hi,
on MacOS, i had to turn of debugger AND activate threads in the compiler options
Otherwise i had crashes
MacBook Pro 14" M1 Pro - 16 Gb - MacOS 14 - Iphone 15 Pro Max - iPad at home
...and unfortunately... Windows at work...
User avatar
pf shadoko
Enthusiast
Enthusiast
Posts: 290
Joined: Thu Jul 09, 2015 9:07 am

Re: Mandelbrot viewer

Post by pf shadoko »

@ Stargate :
juste change "limit" variable (line 3)

@ NicTheQuick : perhaps à problem with ASM version, I don't know much about this subject


I realize that the program is not compatible with PB 32 bit, sorry...
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Mandelbrot viewer

Post by wilbert »

NicTheQuick wrote:I've got an illegal instruction error. On every run the position is somewhere else.
In German it says: "[ERROR] Illegale Anweisung. (Ausführen von binären Daten?)"
Freely translated to: "[ERROR] Illegal instruction. (Exexution of binary data?)"

Are there maybe assembler instructions which my CPU is too old for? It's an Intel Core i7-3820QM wit the following flags:
fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm cpuid_fault epb pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms xsaveopt dtherm ida arat pln pts md_clear flush_l1d
The instructions that are used require a cpu with AVX2 support.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
NicTheQuick
Addict
Addict
Posts: 1226
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Mandelbrot viewer

Post by NicTheQuick »

wilbert wrote:The instructions that are used require a cpu with AVX2 support.
Thanks wilbert. Now it all makes sense. :-) Then at least my guess pointed into the right direction.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
Post Reply